Concordion - how can i set a value into a table? - concordion

At some stage in a concordion test I have, I set a value to some random number.
This value is passed along, and later on , I have some output. The output is "checked" using the concordion "table" setup, where i compare an output value to what I expect it to be.
The problem I have is that I would like to check against the random number mentioned above. When I get the random number, I can set it to something Concordion can store -
<span c:set="#prefixValue">Bob</span>
Well, you get the idea - I replace "Bob" with a getter for my value.
But when I try to use it:
<table c:execute="#actual = getValue(#report, #xpath)">
<tr>
<th>Field name</th>
<th c:assertEquals="#actual">Value</th>
<th c:set="#xpath">Xpath</th>
</tr>
<tr>
<td>UnrelatedValue</td>
<td>SomeDeterminateValue</td>
<td>theXpathForThisToCompareTo</td>
</tr>
<tr>
<td>prefix</td>
<td><span c:echo="#prefixValue" /></td>
<td>differentXpathForThisToCompareTo</td>
</tr>
The whole shebang grinds to a halt, complaining that
"
Commands must be placed on elements when using 'execute' or 'verifyRows' commands on a <table>.
"
How can I use a pre-determined value in a table in Concordion?

The specs aren't supposed to have random elements in them. They're supposed to contain a specific example or set of examples. Rather than using a random number, hardcode a particular value and then you can use it later on.
To tell the fixture about the hardcoded value you can do this:
<span c:execute="setPrefixValue(#TEXT)">Bob</span>
Then in the fixture:
public void setPrefixValue(String prefixValue) {
// TODO: Whatever system configuration you need to do
}
If it isn't actually possible to set the value in your system under test, then use your fixture code to map between the hardcoded value and the actual random value.
public String getValue(String report, String xpath) {
String value = report(report).get(xpath);
if (value.equals(knownRandomValue)) {
return hardcodedValue;
}
return value;
}

Oh Lord! I didn't realise Concordion was going to get all rigid on me.
To fix, I had to alter the Concordion method I was using to be less stupidly rigid.
Following the general ideas here:
http://automatingsoftwaretesting.wordpress.com/2011/05/27/write-your-own-concordion-command-an-example-for-asserting/
I wrote this:
#Override
public void verify(CommandCall commandCall, Evaluator evaluator, ResultRecorder resultRecorder) {
Object expected = evaluator.evaluate(commandCall.getChildren().get(0).getExpression());
Object actual = evaluator.evaluate(commandCall.getExpression());
Element element = setupTheGoshDarnElement(commandCall, expected);
if (actual.equals(expected)) {
resultRecorder.record(Result.SUCCESS);
announceSuccess(element);
} else {
resultRecorder.record(Result.FAILURE);
announceFailure(element, expected.toString(), actual);
}
}
private Element setupTheGoshDarnElement(CommandCall commandCall, Object expected) {
Element e = commandCall.getElement();
e.appendText(expected.toString());
return e;
}
private void announceFailure(Element element, String expected, Object actual) {
listeners.announce().failureReported(new AssertFailureEvent(element, expected, actual));
}
private void announceSuccess(Element element) {
listeners.announce().successReported(new AssertSuccessEvent(element));
}
And so made a new "evaluator" ~ the rest of the evaluator is identical to the AssertEqualsCommand, if you're wondering.
This neatly checks the element and evaluates. Why concordion didn't do this ~ it isn't rocket science at all ~ is beyond me!
NOTE that I still need to use the "expanded table" in my question to get this to work, the short-form table has it's own issues with evaluating inner expressions.

Related

How to sort table in jhipster? Not sure how it works

I've been learning jhipster for the past week now and I'm trying to implement a sortable table. I wanna ask how does the jhiSort and jhiSortBy work? I don't quite understand what does the predicate, ascending and callback function in jhiSort do. Also, which files do the id, date and amount in jhiSortBy come from and how does jhiSortBy work?
<tr jhiSort [(predicate)]="predicate" [(ascending)]="reverse" [callback]="transition.bind(this)">
<th jhiSortBy="id"><span>ID</span> <span class="fa fa-sort"></span></th>
<th jhiSortBy="date"><span>Date</span> <span class="fa fa-sort"></span></th>
<th jhiSortBy="amount"><span>Amount</span> <span class="fa fa-sort"></span></th>
</tr>
jhiSort and jhiSortBy are two directives provided by JHipster that help you implement sorting in data tables. You can see exactly what they do in the links I've provided.
jhiSortBy
The call you see in the header of each column just tells the jhiSortBy directive the name of the attribute it will sort the table by. In your case this means id, date and amount are all attributes of the entities being listed in your table.
This directive handles the user interaction and calls jhiSort to do the actual sorting, plus some extra steps to manage icon changes.
jhiSort
This directive has three properties:
#Input() predicate: string;
#Input() ascending: boolean;
#Input() callback: Function;
When you do [(predicate)]="predicate" you are telling angular that the predicate property of the jhiSort directive (left hand side of the assignment) will bind to a property in your component of the same name (right hand side). So in your *.component.ts you must have a property named predicate that will store the sorting information.
The directive has also a boolean property named ascending, when you do [(ascending)]="reverse" you are telling angular to bind the ascending directive property to a component property named reverse, just like before but this time the names don't match. This property controls only the sorting direction (ascending or descending).
Finally, callback is just the method that will be called on user interaction (click on a table header) to put everything in motion. transition is the name of such method in your *.component.ts, and it looks something like this:
transition(): void {
this.router.navigate(['./'], {
relativeTo: this.activatedRoute.parent,
queryParams: {
page: this.page,
sort: this.predicate + ',' + (this.ascending ? 'asc' : 'desc'),
},
});
}
This will force a navigation change so that the new order and page information persist on the URL, allowing future navigation events to get back without resetting the table.
This navigation change eventually calls loadAll() sending a query to your server-side with the new ordering (and paging) parameters.
The result of this query (a properly ordered list of entities) will be later sent back to the client-side to be displayed.
Very roughly this is how they work.
I is not working correctly:
I found the solution,
it is related to the method
fillComponentAttributesFromResponseBody
change the content of that method to be like this::
protected fillComponentAttributesFromResponseBody(data: IReferences[] | null): IReferences[] {
const referencesNew = [];
if (data) {
for (const d of data) {
if (referencesNew.map(op => op.id).indexOf(d.id) === -1) {
referencesNew.push(d);
}
}
}
return referencesNew;
}
and it will work.
enjoy

Access filter result Angular 6

How can I access filteredArray in my .ts component? Because right now it is accessible only inside ng-container.
<ng-container *ngIf="(userList | filter: 'name' : value) as filteredArray">
<tr *ngFor="let user of filteredArray">
<td>{{user.name}}</td>
<td>{{user.group}}</td>
</tr>
<div>Count: {{ filteredArray.length }}</div>
</ng-container>
How can I modify the code in order to obtain what I want? Thank you for your time!
To answer your question directly: it's not possible the way you describe it. But read on.
Pipes (sometimes still called "filters") should be used only to format data, i.e. prepare it in a human-readable form. For example, the build-in date pipe can be used to transform an ISO string to a string such as "March 21st, 1995", which is how a human from the USA might expect to read the date.
The way you're using pipes is not recommended, precisely because of the question you have. You've essentially put application logic inside a template, which is an anti-pattern and beats the purpose of having easy-to-read declarative templates, which Angular uses in order to figure out how to update DOM.
You should move the filtering logic back to the class. For example, instead of setting this.userList = xxx, you could have a function which you call every time, such as this.changeUserList(xxx).
changeUserList (list) {
this.userList = list
this.filteredArray = list.filter(...)
}
You can put this logic in a setter as well, which allows you to run custom code when you write the usual this.userList = list, but you'll need a separate (usually prefixed private) property on the class where you'd actually store the value. It's not really a limitation since you can also have a trivial getter, so you can still us this.userList normally as a getter without having to remember to use this._userList, essentially tucking this away as the get/set pair's implementation detail.
private _userList
public set userList (list) {
this._userList = list
this.filteredArray = list.filter(...)
}
public get userList (list) { return this._userList }
Observables could really come in handy here as well, since you could just rx.map the userList$ to filteredArray$ with an Array#filter.
public userList$
public filteredArray$ = this.userList$.pipe(map(arr => arr.filter(...))
Then in the template, you can use the async pipe.
*ngIf="filteredArray$ | async as filteredArray"
Avoid doing the following.... but it works for demo purposes 😃
Create a component (e.g. demo-element.component.ts) that takes a single #Input() value:any
Add this new component as the first child of the <ng-container>, and give it a template reference #containerRef e.g.:
<ng-container *ngIf="(userList | filter: 'name' : value) as filteredArray">
<demo-element #containerRef [value]="filteredArray"></demo-element>
In your main component, add
#ViewChild('containerRef') ref;
ngAfterViewInit() {
this.filteredArray = this.ref.value; // Terrible pattern, but answers the question:-)
}
I hope this below code will help you.
<div class="rsrvtn_blk" *ngIf="(items | fSearch:firstname) as filteredItems">
<div class="col-md-3 pl-0" *ngFor="let item of filteredItems">
// you can display the filtered content here
</div>
</div>

Adding Substring in table loop in Html.DisplayFor

Im just asking how to implement Substring code in Razor Html DisplayFor
Actually It was working before then I added the Substring to get the first 5 number in the table then I encountered an error
An exception of type 'System.InvalidOperationException' occurred in System.Web.Mvc.dll but was not handled in user code
Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
Here are my set of Codes:
<tbody>
#for (var i = 0; i < Model.Cards.Count; ++i)
{
var counter = i + 1;
<tr>
<td valign="middle">
<p class="small">#counter</p>
</td>
<td valign="middle">
<p class="small">#Html.DisplayFor(x => x.Cards[i].Number.Substring(0,5))</p>
</td>
</tr>
}
</tbody>
Thanks in Advance !
As Stephen said in comments, using .Substring in the middle of your view doesn't really make sens.
Instead, in your ViewModel (the one which defines your Number property), add the following property :
public string DisplayableNumber => Number.Length > 5 ? Number.ToString().Substring(0, 5) : "WhatYouWantHere";
This will work for C# 5+, else you can use the old way and initialize it in the default constructor.
Then, use it in your view :
#Html.DisplayFor(x => x.Cards[i].DisplayableNumber)
Plus, this is good practice to use this type of property in ViewModel, as Views should't handle any logic.

angular 2+ component with attribute name and no parameters

I want to allow a user to provide a list of one-word attributes without parameter values. For example,
<container row crosscenter wrap spacearound ...>
which results in something like this in container.html
<div [ngClass]="{ 'flexDisplay': true, 'directionRow': isRow, 'directionCol': isCol, 'contentSpaceAround': isSpaceAround}" ...>
What I'm missing is how to set
#Input('row') isRow = false;
to true if 'row' was present in the container line.
Any ideas?
Thanks in advance.
Yogi
This can be handled in ngOnChanges. The value can be assigned either back to input property or to some object that will be passed to ngClass
ngOnChanges(changes: SimpleChanges) {
if ('foo' in changes) {
this.options.foo = true;
}
}
Since there's no way how inputs can become unassigned, there's no reason to provide bindings for them. #Attribute can be used instead:
constructor(#Attribute('foo') public foo: boolean|null) {
this.foo = (foo != null);
}
Using attributes for regular options isn't a good decision, design-wise. This prevents from setting them dynamically. Instead, it is always preferable to accept options input. If all options are supposed to be flags, it can be a string input that will be split and processed in ngOnChanges, like:
<container options="row crosscenter wrap spacearound">
or
<container [options]="'row crosscenter wrap spacearound'">
I think the answer to my question is to create directives for each of the "one-word" tags (attributes) I want to use.
:-)

How to access the elements in the set returned by an Alloy function?

I have an Alloy function in my model like:
fun whichFieldIs[p:Program, fId:FieldId, c:Class] : Field{
{f:Field | f in c.*(extend.(p.classDeclarations)).fields && f.id = fId}
}
This function is working in my model and can return a set of elements such as:
{Field$0, Field$1}
although the function return is not "set Field". I already saw this through the Alloy evaluator tool (available in alloy4.2.jar). What i am trying to do is getting the first element of this set in another predicate, for instance:
pred expVarTypeIsOfA[p:Program, exprName:FieldId, mClass:Class, a:ClassId]{
let field = whichFieldIs[p, exprName, mClass],
fieldType = field[0].type
{
...
}
}
Even when i change the return of the function to "set Field", the error "This expression failed to be typechecked" appears. I only want to get the first element of a set returned by a function, any help?
Does the order really matter in that case? If so, you should take a look at this: seq
In the following example, for each person p, "p.books" is a sequence
of Book:
sig Book { }
sig Person {
books: seq Book
}
...So if s is a sequence of Book, then the first element is s[0]...
seq is now a reserved word, but is nothing more than a relation Int -> Elem.
If it does not matter, you could use an adequate quantifier, e.g.:
pred expVarTypeIsOfA[p:Program, exprName:FieldId, mClass:Class, a:ClassId]{
some field: whichFieldIs[p, exprName, mClass] | {
field.type ...
}
}