Flutter: validating Radix 10 numbers - validation

I was testing validation of numbers on my iPhone.
Here is my code snippet:
child: new TextFormField(
controller: sales,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration: const InputDecoration(
filled: true,
fillColor: CupertinoColors.white,
border: const OutlineInputBorder(),
labelText: ‘Sale amount’,
suffixText: ‘ZAR’,
suffixStyle:
const TextStyle(color: Colors.green)),
maxLines: 1,
validator: (val) {
if (val.isEmpty ) return 'Amount is required';
if (val.contains(",")) {
sales.text = val.replaceAll(new RegExp(r","), ".");
}
if (sales.text.indexOf(".") != sales.lastIndexOf(".")) {
return 'Enter valid amount.';
}
else
return null;
},
),
Now, I'm testing the validation with this number 25,52,85 - this is obviously not a valid number but it is a possibility that is allowed on iPhone's number softkeyboard. (Also interesting to note, on the US iPhone, we have commas on the number softkeyboard instead of fullstop and if one had to store a double, the commas have to be converted into fulstops, which I have done in the validate method in the code above)
Now, when I click "Done" to validate the form, an error results in the log and it tells me that it is an invalid Radix 10 number. In other words, Flutter is telling me that a double cannot exist with two commas / fullstops within it.
So to solve this, I wrote in this piece of code under validate to test if the number contains more than 2 fullstops:
if (sales.text.indexOf(".") != sales.lastIndexOf(".")) {
return 'Enter valid amount.';
}
However, I find this to be cumbersome and was wondering if there was a way to test this more elegantly? How can I validate that a number is a valid number in flutter easily?

.parse is your guy. Either double.parse in case you want decimals, or int.parse if you did not.
Check this other StackOverFlow answer that explains this with examples

Related

how should i find a global key in flutter driver test?

Normally I put Key: ValueKey in a flutter element that I want to find in my test cases for testing, however this particular element already has a globalKey. So, what should I use to find the globalkey used in the element?
value key
key: ValueKey('nameField')
In test case =>
final nameField = find.byValueKey('nameField')
global key
final LabeledGlobalKey<FormFieldState<String>> _passwordField = LabeledGlobalKey<FormFieldState<String>>("passwordFieldKey")
key: _passwordField
In test case =>
final passwordField = find.???('???')
I don't think it's possible to find a GlobalKeys (that I used to find the position of certain widgets), but what you can find is Keys. So what I did is: Wrap the widget that I had to find in my test by a Container Widget that had that GlobalKey.
GlobalKey someKeyName = GlobalKey();
Container(
key: someKeyName,
child: CustomButton(
key: Key('Key that I would look for in my Integration Test'),
child: Text('Press Me'),
),
);
I am not sure of what LabeledGlobalKey<FormFieldState<String>> does, but hope this work around will help you solve your issue.

Is there an Array equality match function that ignores element position in jest.js?

I get that .toEqual() checks equality of all fields for plain objects:
expect(
{"key1":"pink wool","key2":"diorite"}
).toEqual(
{"key2":"diorite","key1":"pink wool"}
);
So this passes.
But the same is not true for arrays:
expect(["pink wool", "diorite"]).toEqual(["diorite", "pink wool"]);
There does not seem to be a matcher function that does this in the jest docs, i.e. that tests for the equality of two arrays irrespective of their elements positions. Do I have to test each element in one array against all the elements in the other and vice versa? Or is there another way?
There is no built-in method to compare arrays without comparing the order, but you can simply sort the arrays using .sort() before making a comparison:
expect(["ping wool", "diorite"].sort()).toEqual(["diorite", "pink wool"].sort());
You can check the example in this fiddle.
As already mentioned expect.arrayContaining checks if the actual array contains the expected array as a subset.
To check for equivalence one may
either assert that the length of both arrays is the same (but that wouldn't result in a helpful failure message)
or assert the reverse: That the expected array contains the actual array:
// This is TypeScript, but remove the types and you get JavaScript
const expectArrayEquivalence = <T>(actual: T[], expected: T[]) => {
expect(actual).toEqual(expect.arrayContaining(expected));
expect(expected).toEqual(expect.arrayContaining(actual));
};
This still has the problem that when the test fails in the first assertion one is only made aware of the elements missing from actual and not of the extra ones that are not in expected.
Put the elements into a set. Jest knows how to match these.
expect(new Set(["pink wool", "diorite"])).toEqual(new Set(["diorite", "pink wool"]));
this does not answer the question exactly, but still may help people that end up here by google search:
if you only care that a subset of the array has certain elements, use expect.arrayContaining() https://jestjs.io/docs/en/expect#expectarraycontainingarray
e.g.,
expect(["ping wool", "diorite"])
.toEqual(expect.arrayContaining(["diorite", "pink wool"]));
Another way is to use the custom matcher .toIncludeSameMembers() from jest-community/jest-extended.
Example given from the README
test('passes when arrays match in a different order', () => {
expect([1, 2, 3]).toIncludeSameMembers([3, 1, 2]);
expect([{ foo: 'bar' }, { baz: 'qux' }]).toIncludeSameMembers([{ baz: 'qux' }, { foo: 'bar' }]);
});
It might not make sense to import a library just for one matcher but they have a lot of other useful matchers I've find useful.
What about checking the content and the length?
expect(resultArray).toEqual(expect.arrayContaining(expectedArray));
expect(resultArray.length).toEqual(expectedArray.length);
If you want to compare two arrays in JEST use the bellow model.
Official link: https://jestjs.io/docs/en/expect#expectarraycontainingarray
const array1 = ['a', 'b', 'c'];
const array2 = ['a', 'b', 'c'];
const array3 = ['a', 'b'];
it("test two arrays, this will be true", () => {
expect(array1).toEqual(expect.arrayContaining(array2));
});
it("test two arrays, this will be false", () => {
expect(array3).toEqual(expect.arrayContaining(array1));
});
You can combine using sets as stated in this answer with checking length of actual result and expectation. This will ignore element position and protect you from duplicated elements in the same time.
const materials = ['pink wool', 'diorite'];
const expectedMaterials = ['diorite', 'pink wool'];
expect(new Set(materials)).toEqual(new Set(expectedMaterials));
expect(materials.length).toBe(expectedMaterials.length);
EDIT: As there is suggested in comment below, this will only work for arrays with unique values.
If you don't have array of objects, then you can simply use sort() function for sorting before comparison.(mentioned in accepted answer):
expect(["ping wool", "diorite"].sort()).toEqual(["diorite", "pink wool"].sort());
However, problem arises if you have array of objects in which case sort function won't work. In this case, you need to provide custom sorting function.
Example:
const x = [
{key: 'forecast', visible: true},
{key: 'pForecast', visible: false},
{key: 'effForecast', visible: true},
{key: 'effRegForecast', visible: true}
]
// In my use case, i wanted to sort by key
const sortByKey = (a, b) => {
if(a.key < b.key) return -1;
else if(a.key > b.key) return 1;
else return 0;
}
x.sort(sortByKey)
console.log(x)
Hope it helps someone someday.
Still a work in progress, but this should work albeit, the error messages may not be clear:
expect.extend({
arrayContainingExactly(receivedOriginal, expected) {
const received = [...receivedOriginal];
if (received.length !== expected.length) return {
message: () => `Expected array of length ${expected.length} but got an array of length ${received.length}`,
pass: false,
};
const pass = expected.every((expectedItem, index) => {
const receivedIndex = findIndex(received, receivedItem => {
if (expectedItem.asymmetricMatch) return expectedItem.asymmetricMatch(receivedItem);
return isEqual(expectedItem, receivedItem);
});
if (receivedIndex === -1) return false;
received.splice(receivedIndex, 1);
return true;
});
return {
message: () => 'Success',
pass,
}
}
});
Then use it like this:
expect(['foo', 'bar']).arrayContainingExactly(['foo']) // This should fail
or
expect({foo: ['foo', 'bar']}).toEqual({
foo: expect.arrayContainingExactly(['bar', 'foo'])
}) // This should pass
We are looping through each value and removing it from the received array so that we can take advantage of the asymmetric matching provided by Jest. If we just wanted to do direct equivalency this could be simplified to just compare the 2 sorted arrays.
Note: This solution uses findIndex and isEqual from lodash.
You can use jest toContainEqual to check if an array contains an element. Then just do that for each element in your expected array:
const actual = [{ foobar: 'C' }, { foo: 'A' }, { bar: 'B' }];
const expected = [{ foo: 'A' }, { bar: 'B' }, { foobar: 'C' }];
expect(actual).toContainEqual(expected[0]);
expect(actual).toContainEqual(expected[1]);
expect(actual).toContainEqual(expected[2]);
(Or put the expect statement in a loop if you have too many elements to check)

Fullcalendar adding event with fixed end time

This is probably an easy one for those who know this thing. :)
Given this:
$(this).fullCalendar('renderEvent',
{
title: 'Class',
start: date,
end: date.setHours(2),
allDay: false
}, true );
Which doesn't work... what's the syntax for setting the end time to two hours past the time that was clicked on? So if the user clicks on 8 AM, I want it to automatically end two hours later, at 10 AM.
And... is it possible to make it so the event length cannot be resized? As in, remove the little UI thing that they can click on to increase or decrease the size?
Thanks!
I figured it out (mostly). in the above example, end: date.setHours(2) of course doesn't work. Upon inspecting the date object passed into dayClick, I found fromNow and when I tried date.fromNow(2), it worked!
The only issue I have now (unrelated to my original question) is that it's prompting me for the event name even though I'm specifying it in the code. Here's the final, working version of what I posted above:
$('#calendar').fullCalendar('renderEvent',
{
id: 0,
title: 'Class',
start: date,
end: date.fromNow(2),
allDay: false
}, true );

Check for negative numbers in Jquery Validation plugin

I am trying to set-up the jquery validation plugin and one of my inputs requires a number within the range of -121 and -123.
I have tried using the range() method :
$("#myform").validate({
rules: {
field: {
required: true,
range: [-121, -123]
}
}
});
However it doesn't allow any numbers to validate. I have tried using max/min as well but they too don't seem to work on negative numbers. Am I missing something?
Thanks
Does the smaller number need to be first? If so, you want range: [-123, -121] instead.
$.validator.addMethod('inputClassName',
function (value) {
return (Number(value) >= -123 && Number(value) <= -121);
}, 'Enter a number between -121 and -123');
You could add this custom validator method, just replace the inputClassName

How to check if a property constains a space in groovy?

I am new to grails, and I am having a problem on how to write the proper constraints of one of the properties of my class. I want to check if the input contains a space (' '). Here is my code..
static constraints = {
username nullable: false, blank: false, minSize: 6, matches: /[A-za-z0-9_]{6,}/, validator: {
Account.countByUsername(it) < 1
}
Please help me.
Thanks!
You would want to use a custom validator like:
username validator: { val -> if (val.contains(' ')) return 'value.hasASpace' }
Edit: As R. Valbuena pointed out, you would need to change your countByUsername() validator to a unique: true.
In addition to a custom validator, you can also use the matches validator to ensure that only valid characters are used.
It looks like you're using this in your original question and the regex you're using doesn't allow a space, so a username with a space should fail that validator.
If you want to give a special message to someone if they have a space in it (instead of some other invalid character), then doelleri's answer is the right way to do that.

Resources