How to configure PHP CodeSniffer to allow arrays with any indentation? - phpcodesniffer

I have a custom rule set defined in an XML.
I am used to hit a tab after each => so that, if my array is multi-line, things will align nicely. It became a habit and I use that for single line arrays also. Therefore, a multi-line array might look like this
$array = array(
'something' => array(
'short' => 1,
'longer' => 1,
),
);
The problem is that PHP CodeSniffer is complaining that there is more than 1 space between => and the value (since I always hit tab, there will be more than one space most of the times - of course, depending on the length of the line so far, it can also be a single space sometimes)
I tried adding the T_ARRAY token to the Generic.WhiteSpace.ScopeIndent rule definition but it didn't help
<rule ref="Generic.WhiteSpace.ScopeIndent">
<properties>
<property name="indent" value="4"/>
<property name="ignoreIndentationTokens" type="array" value="T_COMMENT,T_DOC_COMMENT_OPEN_TAG,T_ARRAY"/>
</properties>
</rule>
Is there a solution for this?
UPDATE
Ok, I realised that Generic.WhiteSpace.ScopeIndent has nothing to do with this because it's the Squiz.WhiteSpace.OperatorSpacing that is enforcing this rule. Now, according to the docs I can't configure this property to exclude the => operator. Is there any other way of doing this?

Unfortunately, that sniff does not have any config options to ignore this specific case. Besides adding an option to the sniff, you really only have two ways to solve this. Neither are great.
1. You can exclude the Squiz.WhiteSpace.OperatorSpacing.SpacingAfter error code in your ruleset. This will still allow the sniff to produce errors for spacing before operators and around bitwise operators, but you wont get any errors for when you have multiple spaces after a standard operator.
To exclude the error code, you would add this to your ruleset:
<exclude name="Squiz.WhiteSpace.OperatorSpacing.SpacingAfter"/>
2. You can write a custom sniff that extends PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\OperatorSpacingSniff and overrides the isOperator() method. Your overridden method would detect the T_DOUBLE_ARROW token and return false, which will cause the main sniff code to stop checking double arrows. If it's not a double arrow, you can throw the request back to the parent class.
If you do this, you need to maintain your own standard with sniffs, which means putting a directory somewhere, with a Sniffs sub-directory structure to hold your sniff.

Related

Cypress, page content and variables

Right or wrong: In Cypress, its impossible to read a value on page X, then keep this value and compare it to a value on page Y.
I can read a value from the page and log it:
cy.get('[data-e2e-selector=whatever]').then(elm => cy.log('Value from page X : ' + elm))
or, for instance, the number of elements with similar or partially matchin selectors:
cy.get('[data-e2e-selector=^whatever]').then(elm => cy.log('Number of elements like this on page X: ' + elm.length))
Hoever, I cannot create a variable of this, because of the asynchronous way Cypress runs. Right? Any value created to just be blank.
Nor can I pass the value read to a method, which in turn compares it to the value on the next page:
compareToValueOnNextPage(cy.get('[data-e2e-selector=^whatever]').then(elm => elm.length));
compareToValueOnNextPage(value: number) { // NB: Not sure if it's a number or string yet...
cy.get('[data-e2e-selector=^whateverNextPage]').then(elm => elm.length).should('have.length', 4)
}
Basically, if I want to compare values, the either have to be on the same page, or they need to be hard-coded. This is a huge limitation when actually end-to-end testing some applications. Very often, a value is created on page X, based on input which should in many cases ba random, thus creating a dynamic value in the test. Then, on page Y, that same value is fetch (from the backend) or shown in some other way, in a Summary etc. And, naturally, I want to compare the value shown on page X to the one shown on page Y/Summary. But this is not possible, due to the very unit-testing thinking that seems to be the foundation for Cypress.
Or am I missing something here? Are there ways around this that aren't ugly/smelly? I think it's possible to store the value on page X in a file, then read that file on page Y. However, Cypress seems to only have one option when reading the file, and that's reading the whole file and looking for a match. So that file would be a mess. Or I'd need several files.
I realize this is kind of trying to impose non-functional ways on a quite functional and asynchroeous technology. However, if it's not possible to "keep" a value and use it later, it's very limiting when it comes to end-to-end testing (even though it's not when the testing is unit-based on frontend components).
UPDATE:
As per Kerrry's suggestion in the answer below:
cy.get('[data-e2e-selector=dellan-accordion]')
.then(elm => cy.wrap(elm.length).as("myVariableName"));
-GO TO NEXT PAGE-
cy.get('[data-e2e-selector=betalingsplan-dellan]')
.then(elm => elm.length)
.should('have.length', myVariableName)
This yeilds "expected 4 to have property 'length'.
This means, obviously, that I cannot get the length of the length.
So I replace 'have.length' with 'eq':
cy.get('[data-e2e-selector=betalingsplan-dellan]')
.then(elm => elm.length)
.should('have.length', myVariableName)
And I get the following error:
expected 4 to equal 0
So, it seems that the first variable - myVariable - is gone after the first cy.get().
If I do everything inside one get (have another get inside that, where I go to the next page AND get the count of the elements), then it works. But the way Kerry shows it, it would be much more flexible. But, alas, the above error.
As jonrsharpe mentioned in the comments, please read the Cypress document on variables and aliases thoroughly. This is a core concept of Cypress, and it will give you a solid understanding of how to implement variables and carry the values between test steps.
The reader's digest example of what you how you can achieve is this:
cy.get('[data-e2e-selector=^whatever]')
.then(elm => cy.wrap(elm.length).as("myVariableName"));
What this is doing is cy.wrap will yield the value from elm.length in a Cypress command chain, which then allows you to assign it to an alias "myVariableName".
In your following test step where you want to compare the value on a separate page, you would then access the alias' value in one of two ways:
Using this.
cy.get('[data-e2e-selector=^whateverNextPage]')
.then(elm => elm.length)
.should('have.length', this.myVariableName)
OR
via cy.get()
cy.get("#myVariableName").then(function(variableValue){
cy.get('[data-e2e-selector=^whateverNextPage]')
.then(elm => elm.length)
.should('have.length', variableValue)
})

Refactor Massive Cucumber Step Definition

My team is currently taking our old UI acceptance test scripts and automating them. To do this we are using Jruby, Cucumber and Watir-Webdriver. So far the automation process has been going pretty well. The only problem we have is that our step definitions are starting to get a bit out of hand.
For example, in most of our scenarios is a section like this:
Given I press the SEARCH_BUTTON
Then I should land on the SEARCH_PAGE
and the step definitions look like this:
Given(/I press the (.*)$/) do |buttonName|
if buttonName == 'SEARCH_BUTTON'
eval "$browser.#{$DataHash['home']['searchButton']}.when_present.click"
elsif buttonName == 'LOGIN_BUTTON'
eval "$b.#{$DataHash['loginPage']['loginButton']}.click"
elsif buttonName == 'HOME_BUTTON'
eval "$b.#{$DataHash['mainPage']['HomeButton']}.click"
elsif buttonName == 'ADD_PRODUCT_BUTTON'
#This if else ladder goes on like this for another 300+ lines
...
end
end
The $DataHash variable refers to config.yml, which uses a hash to store all of the different web elements we are using.
config.yml
home:
searchButton: "link(:id => 'searchBtn')"
searchTypeSelectBox: "select_list(:name => 'matchType')"
searchResetButton: "button(:id => 'resetSearch')"
#rest of the elements on the home page...
loginPage:
loginButton: "link(:id => 'login')"
#rest of the elements on the login page...
....
So $browser.$DataHash['home']['searchButton'].when_present.click is equivalent to $browser.link(:id => 'searchBtn').when_present.click
We are using this basic step definition for every button that a user could click, and at this point this one step definition is something like 300+ lines of code. Most of which are single lines like above. Our other step definitions have the same sort of problem. Are there any good ways of refactoring our step definitions to make them less bloated, or at least easier to search through, without making the actual steps any less re-useable?
Initially we thought we could have the same step definition in multiple files based on which page was being tested. So in searchDefinitions.rb there would be a step definition for Given(/I press the (.*)$/) do |buttonName| which only had the different buttons found on the search page. Then in homeDefinitions.rb would be the same step definition but only with code for the home page buttons. Basically breaking up the if-else ladder across multiple files. Of course, Cucumber doesn't allow the same step definition in multiple files so now we're at a bit of a loss.
As you mentioned you can reuse steps see Reuse Cucumber steps. But I personally found it pretty complicated when I tried to do it. So, from my side I suggest you to implement Page Object pattern. The idea is that you describe your pages or even some modules like separate entities which provides you with ability to interact with them. For understanding concept see here. And here you can find some example. Assuming this your step definition would like
Given(/I press the (.*)$/) do |buttonName|
#my_home_page.click_search_button
...
end
end
Where click_search_button method encapsulates your 'ladder' logic to press login button if search button is not present yet.
Hopefully it makes sense for you.
Supposing that the minor differences in the eval lines you show don't matter, extract the hash values that vary into a constant
BUTTON_KEYS = {
'search' => %w(home searchButton),
'login' => %w(loginPage loginButton)
# ...
}
and use it in your step definition:
Given(/I press the (.*) button$/) do |button_name|
keys = BUTTON_KEYS['button_name']
eval "$browser.#{$DataHash['#{keys[0]}']['#{keys[1]}']}.when_present.click"
end
Now you have half as many lines of code and less duplication.
I changed the step regexp to include "button", to remove that duplication from the button names, and the button names to be lowercase, as in normal English. Whether or not you're showing your feature files to non-programmers, Cucumber step names should read like natural language so that you can think about product requirements and not implementation details when you're reading them.
Alternative suggestion, valid if the two levels of keys in the the YAML are not really needed:
You could restructure the YAML like so
search button: "link(:id => 'searchBtn')"
search type select box: "select_list(:name => 'matchType')"
search reset button: "button(:id => 'resetSearch')"
# rest of the elements on the home page...
login button: "link(:id => 'login')"
# rest of the elements on the login page...
# ...
Then you wouldn't need the hash at all, and your step could just be
Given(/I press the (.*)$/) do |element_name|
eval "$browser.#{$DataHash['#{element_name}']}.when_present.click"
end
Or you could convert the YAML entirely into a hash (representing the method as a string and calling it with .send), which would prevent you from making some syntax errors.

Optional part in rails routing path

I am trying to create a route for a page which can have param1 and param2. Param2 is optional part and the code will take a default value if the value is not present. The following is what I am trying to do
match '/school/:dept/:staff/show' => staff#show
match '/school/:staff/show' => staff#show
I have a bunch of statements like the above which seems to be too much of repetition. Is there a better way to do this. This link has an approach using a third party option. Considering it is an older post, looking to see if this is currently supported with rails.
As per: http://asciicasts.com/episodes/203-routing-in-rails-3
We can do this by defining a route like this, directing any matching route to our info#about action. Note that we can nest parentheses when creating optional parameters.
match "/:year(/:month(/:day))" => "info#about"

Symfony2 and Twig Dump Issue

I am running into an issues with dump() in Twig.
I am not able to completely dump the values of the object that I am returning to my twig template. My object, as defined below, is built up of a product object, qty key/val, OnOrder key/val and avgUnitCost key/val.
I AM able to use dump(qty), dump(OnOrder), dump(avgUnitCost) and see the values of these.
I AM NOT able to use dump() on product to see the key/val of the product object. All I get is a white page of death.
I have read elsewhere on stack that it is a memory issue in the php.ini file. This does not seem to fix the issue, I set mine 1024M and it still times out and gives me the white screen.
I have also read this guys article on the same issue: http://hectorpinol.com/twig-debug-in-symfony-2/ ... He thinks it is a "bidirectional association problem".
In any case, here is the code that I am using to pass the object and render my twig template...
return $this->render('TestBundle:Event:view.html.twig', array(
'heading' => 'View Product',
'product' => $product,
'qty' => $qty,
'OnOrder' => $OnOrder,
'avgUnitCost' => $avgUnitCost,
));
Here is the guts of my question:
How can one effectively use twig to access the elements of an object, whether it be dump or some other method. I need to be able to see all of the elements in the object so that I can place them on the page as I need.
Thanks so much for your help!!!
Check LadybugBundle. You can dump everything.
Try adding a break point in twig_var_dump:
/vendor/twig/twig/lib/Twig/Extension/Debug.php (at the bottom)
Then you can use the functionality of your debugger...
Look at this answer: https://stackoverflow.com/a/29302069/4102223
It is my approach to solve this problem, only few lines must to be changed in one place (it is easier because no need to include new bundles and read its documentation).

Redirect Error: No such label 'stdexten' in extension

i have install asterisk 11 on my server but when i want to redirect to extensions, i catch this error:
NOTICE[12657][C-00000043]: pbx.c:4475 pbx_extension_helper: No such label 'stdexten' in extension '305' in context 'DLPN_DialPlan'
WARNING[12657][C-00000043]: pbx.c:11825 pbx_parseable_goto: Priority 'stdexten' must be a number > 0, or valid label
ERROR[12657][C-00000043]: app_stack.c:547 gosub_exec: Gosub address is invalid: '305,stdexten(SIP/305)'
i think that this must be a bug in asterisk. anybody know about this???
I think that you are probably using a Goto with just an extension. This won't work - When using Goto, if you wish to go to a different exntension, then you must also specify the label or line number you want to go to.
Here's a useful reference on Goto in Asterisk
Here are the various combinations of parameters that work:
Goto(context,extension,priority)
Goto(extension,priority)
Goto(priority)
Goto(context,extension,label)
Goto(extension,label)
Goto(label)
Contexts are groups of extensions in extensions.conf. The start of a context looks like this: [Hello_World_Context]
Extensions are groups of commands that get executed if the call matches the number pattern. They're usually a bunch of commands which start with exten =>, such as: exten => 100,1,Answer
A priority is basically a line number. An example: exten => 100,1,Answer has a priority of 1.
A label can be used instead of a priority/line number. Example: exten => 100,n(extension_name),Answer - This has a label of exension_name
Goto([[context|]extension|]priority)
Set the priority to the specified value, optionally setting the extension and optionally the context as well. The extension BYEXTENSION is special in that it uses the current extension, thus permitting you to go to a different context, without specifying a specific extension. Please note that the LEADING arguments to Goto() are optional, not the trailing arguments.

Resources