I've got a function:
public function waitAndFill($element, $value, $timeOut = null)
{
$I = $this;
$I->_waitFor($element, $timeOut);
$I->fillField($element, $value);
$I->seeInField($element, $value);
}
And I use it like this:
$I->waitAndFill('#inputInfo', 'This is test info');
The textarea looks as follows
<textarea id="inputInfo"
name="company_description"
ng-model="company.company_description"
class="form-control"></textarea>
So, my test fails with this:
Step I see in field "#inputInfo","This is test info"
Fail Failed testing for 'This is test info' in company_description's value:
Failed asserting that an array contains 'This is test info'.
It works fine on <input> fields, but fails on <textarea>. Looks like it doesn't see any text at all.
This text is present on the screen shot made by the test.
What am I doing wrong?
It's a bug. The problem is this: $I->seeInField($element, $value); invokes $this->proceedSeeInField(array $elements, $value); which invokes a method getText() on the Facebook\WebDriver\Remote\RemoteWebElement object that it finds. If you read the documentation for Facebook\WebDriver\Remote\RemoteWebElement#getText() method it says that it returns the innerText for that element. So that's no bueno. To workaround this I removed the conditional for the textarea in this function.
protected function proceedSeeInField(array $elements, $value)
{
$strField = reset($elements)->getAttribute('name');
if (reset($elements)->getTagName() === 'select') {
$el = reset($elements);
$elements = $el->findElements(WebDriverBy::xpath('.//option[#selected]'));
if (empty($value) && empty($elements)) {
return ['True', true];
}
}
$currentValues = [];
if (is_bool($value)) {
$currentValues = [false];
}
foreach ($elements as $el) {
if ($el->getTagName() === 'textarea') {
$currentValues[] = $el->getText();
} elseif ($el->getTagName() === 'input' && $el->getAttribute('type') === 'radio' || $el->getAttribute('type') === 'checkbox') {
if ($el->getAttribute('checked')) {
if (is_bool($value)) {
$currentValues = [true];
break;
} else {
$currentValues[] = $el->getAttribute('value');
}
}
} else {
$currentValues[] = $el->getAttribute('value');
}
}
return [
'Contains',
$value,
$currentValues,
"Failed testing for '$value' in $strField's value: " . implode(', ', $currentValues)
];
}
You should change it to:
protected function proceedSeeInField(array $elements, $value)
{
$strField = reset($elements)->getAttribute('name');
if (reset($elements)->getTagName() === 'select') {
$el = reset($elements);
$elements = $el->findElements(WebDriverBy::xpath('.//option[#selected]'));
if (empty($value) && empty($elements)) {
return ['True', true];
}
}
$currentValues = [];
if (is_bool($value)) {
$currentValues = [false];
}
foreach ($elements as $el) {
if ($el->getTagName() === 'input' && $el->getAttribute('type') === 'radio' || $el->getAttribute('type') === 'checkbox') {
if ($el->getAttribute('checked')) {
if (is_bool($value)) {
$currentValues = [true];
break;
} else {
$currentValues[] = $el->getAttribute('value');
}
}
} else {
$currentValues[] = $el->getAttribute('value');
}
}
return [
'Contains',
$value,
$currentValues,
"Failed testing for '$value' in $strField's value: " . implode(', ', $currentValues)
];
}
Now it calls getAttribute('value') just like any other input element.
The is in file WebDriver.php
Related
I am writing this code using Xrm.Webapi.RetreiveRecord as below but I am getting the below error when debugging.
TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
if (typeof (ContosoPermit) == "undefined") { var ContosoPermit = { __namespace: true }; }
if (typeof (ContosoPermit.Scripts) == "undefined") { ContosoPermit.Scripts = { __namespace: true }; }
ContosoPermit.Scripts.PermitForm = {
handleOnLoad: function (executionContext) {
console.log('on load - permit form');
},
handleOnChangePermitType: function (executionContext)
{
console.log('on change - permit type');
},
_handlePermitTypeSettings: function (executionContext) {
var formContext = executionContext.getFormContext();
var permitType = formContext.getAttribute("contoso_permittype").getValue();
if (permitType == null) {
formContext.ui.tabs.get("inspectionsTab").setVisible(false);
return;
} else {
var permitTypeID = permitType[0].id;
debugger;
Xrm.WebApi.retrieveRecord("contoso_permittype", permitTypeID).then(
function success(result) {
if (result.contoso_requireinspections) {
formContext.ui.tabs.get("inspectionstab").setVisible(true);
}
else {
formContext.ui.tabs.get("inspectionstab").setVisible(false);
}
},
function (error) { alert('Error' + error.message) });
}
},
__namespace: true
}
I am inserting the data. The data is being entering quite fine but whenever I enter a letter the entry is done but that entry is converted to '0'.
This is my controller store function:
public function store(GuidanceReportRequest $request)
{
$stats = GuidanceReport::where('user_id', $request->user_id)->whereDate('created_at', now())->count();
if ($stats > 0) {
Session::flash('warning', 'Record already exists for current date');
return redirect()->route('reports.index');
}
if ((!empty($request->call_per_day[0]) && !empty($request->transfer_per_day[0])) ||
(!empty($request->call_per_day[1]) && !empty($request->transfer_per_day[1])) || (!empty($request->call_per_day[2])
&& !empty($request->transfer_per_day[2]))
) {
foreach ($request->category as $key => $value) {
$catgeory_id = $request->category[$key];
$call_per_day = $request->call_per_day[$key];
$transfer_per_day = $request->transfer_per_day[$key];
if (!empty($catgeory_id) && !empty($call_per_day) && !empty($transfer_per_day)) {
GuidanceReport::create([
"user_id" => $request->user_id,
"categories_id" => $catgeory_id,
"call_per_day" => $call_per_day,
"transfer_per_day" => $transfer_per_day,
]);
}
}
} else {
GuidanceReport::create($request->except('category', 'call_per_day', 'transfer_per_day'));
}
Session::flash('success', 'Data Added successfully!');
return redirect()->route('reports.index');
}
This is my Validation Request code
public function rules()
{
$rules = [];
$request = $this->request;
if ($request->has('transfer_per_day')) {
if (!empty($request->transfer_per_day)) {
$rules['transfer_per_day'] = "numeric";
}
}
if ($request->has('call_per_day')) {
if (!empty($request->call_per_day)) {
$rules['call_per_day'] = "numeric";
}
}
if ($request->has('rea_sign_up')) {
if (!empty($request->rea_sign_up)) {
$rules['rea_sign_up'] = "numeric";
}
}
if ($request->has('tbd_assigned')) {
if (!empty($request->tbd_assigned)) {
$rules['tbd_assigned'] = "numeric";
}
}
if ($request->has('no_of_matches')) {
if (!empty($request->no_of_matches)) {
$rules['no_of_matches'] = "numeric";
}
}
if ($request->has('leads')) {
if (!empty($request->leads)) {
$rules['leads'] = "numeric";
}
}
if ($request->has('conversations')) {
if (!empty($request->conversations)) {
$rules['conversations'] = "numeric";
}
}
return $rules;
}
Although I check the type in which request is being sent from controller and recieved from the request validation and it is Object. So how can I solve the issue.
I'm trying to validate a schema for complex JSON. We can easily compare a schema with API response by below command
And match response == response_SCHEMA
(where "response_SCHEMA" is json schema)
For small json we can manually create:
Actual API response:
{ "id": "123", "name": "abc", "type": "Mumbai", "owner": { "name": "Mr Singh", "type": "Business", "licenseNo": "ASL8989" }
Converted the response to below - manually
{ "id": "#number", "name": "#string", "type": "#string", "owner": { "name": "#string", "type": "#string", "licenseNo": "#string" }
How to create this kind of schema automatically for a complex big json having 300-400 lines? So, we can compare it with API response with Karate.
The point of the schema design is that you can easily cut and paste an actual JSON and either use it as it is (data match, recommended) or edit it to use #string etc (schema match).
When you say 300-400 lines, most likely you mean an array of JSON. All you need to do is specify the schema of the "repeating part" and then use match each: https://github.com/intuit/karate#match-each
* def actual = [{ a: 1, b: 'x' }, { a: 2, b: 'y' }]
* def schema = { a: '#number', b: '#string' }
* match each actual == schema
The short answer is there is no automatic way to do it. Typically you never need to do more than a few lines. Maybe you can write your own custom utility.
#Mayank I also faced this issue, Unfortunately I didn't find any options.
So I created my own small JS to convert the actual JSON into JSON Schema which is compatible with Karate Fuzzy Match.
The output may look like this
enter image description here
Hope This Helps!...
function main() {
var json;
if (document.getElementById('code').value) {
try {
json = JSON.parse(document.getElementById('code').value);
document.getElementById('code').value = JSON.stringify(inputTxt, null, 2);
document.getElementById('output').value = '';
} catch (e) {
document.getElementById('output').value = e;
}
}
let outArr = {};
let output = convertJson(json, 'response', true);
ouput = Object.assign(output, outArr);
Object.keys(ouput).forEach(key => ouput[key] === "#undefined" && delete ouput[key]);
document.getElementById('output').value = JSON.stringify(output, null, 2);
function convertJson(json, keyName, isParent) {
let outA = {};
let x = {};
let y = {};
Object.keys(json).forEach(function(key) {
if (!(getJSType(json[key]) === "object") && !(getJSType(json[key]) === "array")) {
x[key] = '#' + getJSType(json[key]);
}
if (getJSType(json[key]) === "object") {
x[key] = convertJson(json[key], key, false);
}
if (getJSType(json[key]) === "array") {
x[key] = '#' + getJSType(json[key]);
// y[key + 'arr'] = getArray(json[key][0], key, false);
getArray(json[key][0], key, false);
}
})
if (isParent) {
if (Object.keys(x).length > 0) {
outA[keyName] = x;
}
if (Object.keys(y).length > 0) {
outA[keyName + 'Arr'] = y;
}
return outA;
} else {
if (Object.keys(y).length > 0 && isParent) {
return y;
}
if (Object.keys(x).length > 0) {
return x;
}
}
}
function getArray(json, keyName, isParent) {
let z = {};
if (!(getJSType(json) === "object") && !(getJSType(json) === "array")) {
z[keyName + 'Arr'] = '#' + getJSType(json);
} else {
z[keyName + 'Arr'] = convertJson(json, keyName, false);
}
outArr = Object.assign(outArr, z);
}
function getJSType(valToChk) {
function isUndefined(valToChk) {
return valToChk === undefined;
}
function isNull(valToChk) {
return valToChk === null;
}
function isArray(valToChk) {
return valToChk.constructor == Array;
}
function isBoolean(valToChk) {
return valToChk.constructor == Boolean;
}
function isFunction(valToChk) {
return valToChk.constructor == Function;
}
function isNumber(valToChk) {
return valToChk.constructor == Number;
}
function isString(valToChk) {
return valToChk.constructor == String;
}
function isObject(valToChk) {
return valToChk.constructor == Object;
}
if (isUndefined(valToChk)) {
return "undefined";
}
if (isNull(valToChk)) {
return "null";
}
if (isArray(valToChk)) {
return "array";
}
if (isBoolean(valToChk)) {
return "boolean";
}
if (isFunction(valToChk)) {
return "function";
}
if (isNumber(valToChk)) {
return "number";
}
if (isString(valToChk)) {
return "string";
}
if (isObject(valToChk)) {
return "object";
}
}
}
function formatJson() {
if (document.getElementById('code').value) {
try {
var inputTxt = JSON.parse(document.getElementById('code').value);
document.getElementById('code').value = JSON.stringify(inputTxt, null, 2);
document.getElementById('output').value = '';
} catch (e) {
document.getElementById('output').value = e;
}
}
}
function minifyJson() {
if (document.getElementById('code').value) {
try {
var inputTxt = JSON.parse(document.getElementById('code').value);
document.getElementById('code').value = JSON.stringify(inputTxt, null, null);
document.getElementById('output').value = '';
} catch (e) {
document.getElementById('output').value = e;
}
}
}
<html>
<head>
<title>JavaScript Code Runner</title>
</head>
<body>
<h3>Generate the Json Schema for Response</h3>
<div style="display: flex;">
<textarea id="code" style="flex: 1; height: 80vh;" spellcheck="false"></textarea>
<textarea id="output" style="flex: 1; height: 80vh; overflow: auto;" spellcheck="false"></textarea>
</div>
<div style="display: flex;height: 12;"></div>
<button onclick="runCode()">Generate Schema</button>
<button onclick="formatJson()">Format JSON</button>
<button onclick="minifyJson()">Minify JSON</button>
<script src="src/jsonconverter.js"></script>
<script>
function runCode() {
main();
}
</script>
</body>
</html>
I want to inherit function add_product of models.Order.
Here is the original function
/point_of_sale/static/src/js/models.js
add_product: function(product, options){
if(this._printed){
this.destroy();
return this.pos.get_order().add_product(product, options);
}
this.assert_editable();
options = options || {};
var attr = JSON.parse(JSON.stringify(product));
attr.pos = this.pos;
attr.order = this;
var line = new exports.Orderline({}, {pos: this.pos, order: this, product: product});
if(options.quantity !== undefined){
line.set_quantity(options.quantity);
}
if(options.price !== undefined){
line.set_unit_price(options.price);
}
//To substract from the unit price the included taxes mapped by the fiscal position
this.fix_tax_included_price(line);
if(options.discount !== undefined){
line.set_discount(options.discount);
}
if(options.extras !== undefined){
for (var prop in options.extras) {
line[prop] = options.extras[prop];
}
}
var to_merge_orderline;
for (var i = 0; i < this.orderlines.length; i++) {
if(this.orderlines.at(i).can_be_merged_with(line) && options.merge !== false){
to_merge_orderline = this.orderlines.at(i);
}
}
if (to_merge_orderline){
to_merge_orderline.merge(line);
} else {
this.orderlines.add(line);
}
this.select_orderline(this.get_last_orderline());
if(line.has_product_lot){
this.display_lot_popup();
}
},
I need to add one more condidtion like,
if(options.is_promo !== undefined){
line.set_promo(options.is_promo);
}
},
So in my custom module, I tried this,
var _super_order = models.Order.prototype;
models.Order = models.Order.extend({
add_product: function(product, options){
if(options.is_promo !== undefined){
line.set_promo(options.is_promo);
}
_super_order.add_product.apply(this,arguments);
},
But it throws an error, line is not defined.
How can i do it?
I tried doing a search function where the only field would be an <input type='text' /> it'll be stripped into an array() then passed to a whereLoop.
static function generateSearch($fields, $queryString)
{
return function($query) use($queryString, $fields)
{
foreach($fields as $field) {
$query = $query->orWhere($field, 'like', $queryString);
}
$query = $query->whereHas('category', function($_query) use ($queryString)
{
$_query->where('name','like',$queryString);
});
};
}
public static function search($query)
{
$searchBits = explode(' ', $query);
$query = Lead::with(array('user', 'category'));
$ctr = 0;
if(Category::whereIn('name', $searchBits)->count() != 0) {
$query = $query->whereHas('category', function($query) use ($searchBits)
{
$ctr = 0;
foreach($searchBits as $bit) {
$bit = "%".$bit."%";
$callback = "orWhere";
$queryFunc = Lead::generateSearch(array('name'), $bit);
if($ctr == 0) {
$callback = "where";
}
$query = $query->$callback($queryFunc);
}
});
}else {
foreach($searchBits as $bit) {
$bit = "%".$bit."%";
$callback = "orWhere";
$queryFunction = Lead::generateSearch(array('name', 'website', 'name', 'email'), $bit);
if($ctr == 0) {
$callback = "where";
}
$query = $query->$callback($queryFunction);
$ctr++;
}
}
$query = $query->orderBy('id','desc');
return $query;
}
Category only has ONE row as of the moment: its - "hot"
if i type in any keyword, it'll directly go to generateSearch()
but if i type in "hot", it'll send an error
Call to undefined method
Illuminate\Database\Query\Builder::category()
does anybody know what's up?
found the error. after looking deep within the callstack. i should not have added the
$query = $query->whereHas('category', function($_query) use ($queryString)
{
$_query->where('name','like',$queryString);
});
inside the generateSearch() or i should create another function for it. its being called by category callback as well.