I'm new to SpecFlow, and am setting up a number of test features/scenarios that are for authenticated users of different role types. I'm doing this via browser automation with Coypu.
So I have a Background step in the feature to set up the log in of a user in that role type.
Background:
Given I am logged in as a ...some role I'm interested in...
After each scenario in the feature, I want to log the user out again (otherwise the log in step in the Background won't work for the next scenario -- I'm keeping the same Coypu browser instance open in between tests).
I found the [AfterScenario] annotation that I could use, but as this is scoped across all scenarios in all features (as far as I understand...) it would affect scenarios say for unauthenticated users.
I could scope the [AfterScenario] with [Scope(Feature="Some Feature")] I believe, but I'm anticipating having to log in/out before and after a whole number of features that I'm testing, and I'm not keen on specifying all of these with a bunch of magic strings.
So I'm wondering if there's something I can put in the Feature file, kind of the equivalent of Background but to run after each scenario in that feature. (Or alternatively, maybe the way I'm logging in/out for each scenario is not the best way to go about things?)
There is no "Postground" feature in specflow however you can achieve something similar with tags filtering.
In most of our projects we are using tags to mark scenarios which have specific setup/teardown logic.
Then we are using the BeforeScenario/AfterScenario hooks to execute the logic:
[BeforeScenario("authentication")]
public void BeforeAuthenticationScenario()
{
//...
}
[AfterScenario("authentication")]
public void AfterAuthenticationScenario()
{
//...
}
And you can tag individual scenarios or whole features:
#authentication
Feature: Some feature requires authentication
#authentication
Scenario: Some scenario requires authentication
So in your code you will only have one magic string "authentication" and in your features you can apply the custom logic declaratively with the tag.
Related
I'm working on a simple JIRA Server plugin that will prevent a transition from occurring if a certain custom field has not been set. I have created a new workflow validator with atlas-create-jira-plugin-module and tailored the validate function to fit my needs. Strangely, when I add this new validator to a transition via the workflow editor, it appears in the list of validations with the wrong description. It is showing the description from the default condition, "Only users with Resolve Issues" permission can execute this transition".
I've been following along with this tutorial: https://developer.atlassian.com/server/jira/platform/creating-workflow-extensions/
I also came across this similar tutorial: https://www.j-tricks.com/tutorials/workflow-validator
In my atlassian-plugin.xml I made sure to define a "view" velocity resource:
<workflow-validator key="custom-field-is-set-validator" name="Custom Field Is Set Validator" i18n-name-key="custom-field-is-set-validator.name" class="com.ngc.jira.plugins.workflow.CustomFieldIsSetValidatorFactory">
<description key="custom-field-is-set-validator.description">Validation to require that a custom field be given a value.</description>
<validator-class>com.ngc.jira.plugins.workflow.CustomFieldIsSetValidator</validator-class>
<resource type="velocity" name="view" location="templates/validators/custom-field-is-set-validator.vm"/>
<resource type="velocity" name="input-parameters" location="templates/validators/custom-field-is-set-validator-input.vm"/>
<resource type="velocity" name="edit-parameters" location="templates/validators/custom-field-is-set-validator-input.vm"/>
</workflow-validator>
And the contents of custom-field-is-set-validator.vm are as follows:
Only if the custom field <strong>$field</strong> has be set.
As a sanity check, I created a workflow condition and applied my velocity (vm) resource as the view template for it. It shows up correctly within this context!
However, when I try to use the same velocity resource for my workflow validator, the admin page still displays the validator as "Only users with Resolve Issues permission can execute this transition" instead of using my description.
What am I missing? Thanks!
Screenshot showing the built-in condition
Screenshot showing my validator that is wrongly appearing as the same condition
I wrote an O'Reilly book Practical Jira Plugins back in 2011 that has a validator example. The source for this is at https://bitbucket.org/mdoar/practical-jira-plugins/src/default/ (and the book is Out There).
But frankly these days I'd use ScriptRunner, JMWE or other plugins that let you write custom workflow things. But don't let that stop you learning it! Good luck
It turns out, I had copied/pasted a piece of code from my workflow condition that needed to be tweaked for a workflow validator. I was trying to cast to a ConditionDescriptor when I should have been casting to a ValidatorDescriptor:
Bad:
if (!(descriptor instanceof ConditionDescriptor)) {
throw new IllegalArgumentException("Descriptor must be a ConditionDescriptor.");
}
ConditionDescriptor conditionDescriptor = (ConditionDescriptor) descriptor;
Good:
if (!(descriptor instanceof ValidatorDescriptor)) {
throw new IllegalArgumentException("Descriptor must be a ValidatorDescriptor.");
}
ValidatorDescriptor validatorDescriptor = (ValidatorDescriptor) descriptor;
Pretty neat that instead of completely breaking my plugin, it ended up displaying a different description altogether. ;)
I am writing a web application that has a front facing website and then an admin console. I would like to be able to have a setting that when set to true means that a holding or maintenance page is displayed on the front end website.
My routes configuration is currently in a yaml file and is read on on each request. But now I want it to be clever enough to know whether it is in maintenance mode or not and if it is to direct all routes to one specific page. Or it could change the routes so that there is only one.
I have thought that this could be done with different files being loaded based on the setting but then means that all routes are static and cannot be retrieved from a database for example. Additionally I have had problems reading from the database during the setup phase of the request. I configured the system to read from the DB as service but this does not appear to be usable at the setup phase, have i got this wrong?
Any pointers gratefully recieved.
Russell
I often use maintenance page with Silex:
At the same place I define $app['debug'] = true; I also define an other variable $app['maintenance'] = true; that I use for various check.
Among them I define a maintenance page as following:
$app->before(function (Request $request, Application $app) {
if($app['maintenance']){
$subRequest = Request::create('/maintenance', 'GET');
return $app->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
});
$app->get('/maintenance', function () use ($app) {
// Here you can return your maintenance page
return $app->render('maintenance.twig');
});
Then when I turn on the maintenance variable, every request is redirected to the maintenance route.
As you can see I don't use any yaml configuration file in my app, but the idea is the same with them.
I have multiple instances of Adobe Analytics in the same Adobe DTM web property. They all go to different report suites. I'd like to create a page load rule so that the data is only reported to one report suite for any given page. So far the page load rules that I have created are causing the AA data to report to all of the report suites. Does anyone have any idea to get them to only fire to one at a time?
Thanks,
Mike
It is possible to set DTM to suppress the call for an event based rule or direct call rule but currently it is not possible to do it with a page load rule within the DTM built-in interface.
Some things you can do:
1) Combine your Adobe Analytics instances into a single instance. Is there a particular reason you are using multiple instances of Adobe Analytics? I know you mentioned they are for separate report suites, but are they also for separate Adobe Analytics instances altogether? If not, is it because they are completely separate implementations with different variables and logic assigned for them? If the only thing different between them is report suite id, then you should combine them and write some logic to pop relevant report suite id(s) for s.account.
2) Make use of s.abort to suppress the calls. If your code version is H25.3+ or you are using AppMeasurement then you can set s.abort to true to make the next Adobe Analytics request (s.t or s.tl call) be cancelled. Note that this may only be feasible if your instances are all using separate namespaces.. if you are just outputting several instances of code all under the same namespace, you will have issues. Also, if you are doing that, then you may also have issues as far as variables carrying over to other instances. But in any case, basically within your page load rule you'd add a rule condition where criteria is Data:Custom and then you'd write js logic to determine which one(s) you don't want to pop and set [namespace].abort=true; for each of them. Then return true at the end to make sure the condition is always true.
Or, you can set s.abort=true; within the Custom Page Code section for each Adobe Analytics instance you want to suppress in the page load rule. There are various other methods for popping s.abort but hopefully you get the picture. Which one is best just depends on how all your stuff is actually setup.
3) Pop the Adobe Analytics tags as a regular tag instead of a Tool. Remove them as a tool and put them as a Javascript / Third Pary Tag within the page load rule. This includes the core lib code and anything else you may have in the Tool config section. This also means outputting the "trigger" (s.t call). Make a separate one for each one and then you can make conditions for them to pop.
To add to Crayon's answer, you can also choose a custom code implementation in the Library Management section of the tool configuration settings. You will have to paste in the s_code contents and check the box that says "Set report suites using custom code below"
Then, you can use whatever logic you want to set a variable in the code that directs data to the report suites.
if(document.location.href == "http://www.mypage1.com"){
s_account = "rsid_1";
}else{...}
To add to Brett's answer - with rare exception, I let Adobe manage the analytics file. However, you can use the customize page code section within the Adobe Analytics tool configuration to deploy plugins or set the report suite ID dynamically. Here's an example I commonly use:
var suiteid;
var enviro;
var getURL = window.location.href
// Set RSID based on URL
if (getURL.indexOf('myURL.com') != -1)
{
suiteid = 'rsidproduction';
s.linkInternalFilters = 'javascript:,mailto:,tel:,' + window.location.host;
enviro = 'prod';
}
else
{
suiteid = 'rsidstaging';
s.linkInternalFilters = 'javascript:,mailto:,tel:,' + window.location.host;
enviro = 'dev';
}
s.account = suiteid;
This is an easy way to dynamically change the RSID and keep the analytics file managed by Adobe. I also blogged about this here: Managing your RISD Dynamically
I'm new to BDD, Specflow and WatiN. I would like to use these tools to automate acceptance tests for my ASP.NET MVC application.
I've already figured out how to basically use these tools, and I successfully built my first acceptance test: Log on to the website.
Here is the Gherkin for this test:
Feature: Log on to the web
As a normal user
I want to log on to the web site
Scenario: Log on
Given I am not logged in
And I have entered my name in the username textbox
And I have entered my password in the password textbox
When I click on the login button
Then I should be logged and redirected to home
Now, I would like to write a bunch of other tests, and they all require the user to be authenticated. For example:
Feature: List the products
As an authenticated user
I want to list all the products
Scenario: Get Products
Given I am authenticated
And I am on the products page
When I click the GetProducts button
Then I should get a list of products
What bugs me is that to make this test independent of the others, I'd have to write code to log on the website again. Is this the way to go? I doubt.
I'm wondering if there are best practices to follow for testing scenarios like that. Should I keep the browser open and have the tests run in a specific order, on the same browser? Or should I put the MVC application in a specific state?
For this, we have a specific Given step, that looks something like this in Gherkin:
Given I am signed in as user#domain.tld
Like you mentioned, this step basically reuses other steps to sign in the user. We also have an "overload" that takes a password, in case the test user has a non-default test password:
Given I am signed in as user#domain.tld using password "<Password>"
[Binding]
public class SignInSteps
{
[Given(#"I am signed in as (.*)")]
public void SignIn(string email)
{
SignInWithSpecialPassword(email, "asdfasdf");
}
[Given(#"I am signed in as (.*) using password ""(.*)""")]
public void SignInWithSpecialPassword(string email, string password)
{
var nav = new NavigationSteps();
var button = new ButtonSteps();
var text = new TextFieldSteps();
var link = new LinkSteps();
nav.GoToPage(SignOutPage.TitleText);
nav.GoToPage(SignInPage.TitleText);
nav.SeePage(SignInPage.TitleText);
text.TypeIntoTextField(email, SignInPage.EmailAddressLabel);
text.TypeIntoTextField(password, SignInPage.PasswordLabel);
button.ClickLabeledSubmitButton(SignInPage.SubmitButtonLabel);
nav.SeePage(MyHomePage.TitleText);
link.SeeLinkWithText("Sign Out");
}
}
I think this is the best approach, since you should not be able to guarantee that all of the tests run in a specific order.
You may also be able to do this with a SpecFlow tag though, and have that tag execute BeforeScenario. That might look something like this:
Feature: List the products
As an authenticated user
I want to list all the products
#GivenIAmAuthenticated
Scenario: Get Products
Given I am on the products page
When I click the GetProducts button
Then I should get a list of products
[BeforeScenario("GivenIAmAuthenticated")]
public void AuthenticateUser()
{
// code to sign on the user using Watin, or by reusing step methods
}
...should I put the MVC application in a specific state?
When signing in users, it's not the MVC application that needs to be put into a specific state, but rather the browser that needs to be put into a specific state -- namely, writing the authentication cookie. I'm not sure if you can do this or not, given that the auth cookie is encrypted. I always found it easier to just let SF walk though the authentication steps at the beginning of each scenario.
You might want to consider further refining your solution. Have a read of Dan North's Who's Domain is it anyway and then ask yourself if these two scenarios actually belong together. I've found there is value in the approach that danludwig has suggested, but there's more value in separating your scenarios according to their domain. Think of it as refactoring your scenarios.
You can still build one scenario from the activities of another, but ask yourself, do you really need to go through the same steps, or would providing a mocked "Already logged in" object to your session work better.
When creating tests for .Net applications, I can use the White library to find all elements of a given type. I can then write these elements to an Xml file, so they can be referenced and used for GUI tests. This is much faster than manually recording each individual element's info, so I would like to do the same for web applications using Selenium. I haven't been able to find any info on this yet.
I would like to be able to search for every element of a given type and save its information (location/XPath, value, and label) so I can write it to a text file later.
Here is the ideal workflow I'm trying to get to:
navigate_to_page(http://loginscreen.com)
log_in
open_account
button_elements = grab_elements_of_type(button) # this will return an array of XPaths and Names/IDs/whatever - some way of identifying each grabbed element
That code can run once, and I can then re-run it should any elements get changed, added, or removed.
I can then have another custom function iterate through the array, saving the info in a format I can use later easily; in this case, a Ruby class containing a list of constants:
LOGIN_BUTTON = "//div[1]/loginbutton"
EXIT_BUTTON = "//div[2]/exitbutton"
I can then write tests that look like this:
log_in # this will use the info that was automatically grabbed beforehand
current_screen.should == "Profile page"
Right now, every time I want to interact with a new element, I have to manually go to the page, select it, open it with XPather, and copy the XPath to whatever file I want my code to look at. This takes up a lot of time that could otherwise be spent writing code.
Ultimately what you're looking for is extracting the information you've recorded in your test into a reusable component.
Record your tests in Firefox using the Selenium IDE plugin.
Export your recorded test into a .cs file (assuming .NET as you mentioned White, but Ruby export options are also available)
Extract the XPath / CSS Ids and encapsulate them into a reusable classes and use the PageObject pattern to represent each page.
Using the above technique, you only need to update your PageObject with updated locators instead of re-recording your tests.
Update:
You want to automate the record portion? Sounds awkward. Maybe you want to extract all the hyperlinks off a particular page and perform the same action on them?
You should use Selenium's object model to script against the DOM.
[Test]
public void GetAllHyperLinks()
{
IWebDriver driver = new FireFoxDriver();
driver.Navigate().GoToUrl("http://youwebsite");
ReadOnlyCollection<IWebElement> query
= driver.FindElements( By.XPath("//yourxpath") );
// iterate through collection and access whatever you want
// save it to a file, update a database, etc...
}
Update 2:
Ok, so I understand your concerns now. You're looking to get the locators out of a web page for future reference. The challenge is in constructing the locator!
There are going to be some challenges with constructing your locators, especially if there are more than one instance, but you should be able to get far enough using CSS based locators which Selenium supports.
For example, you could find all hyperlinks using an xpath "//a", and then use Selenium to construct a CSS locator. You may have to customize the locator to suit your needs, but an example locator might be using the css class and text value of the hyperlink.
//a[contains(#class,'adminLink')][.='Edit']
// selenium 2.0 syntax
[Test]
public void GetAllHyperLinks()
{
IWebDriver driver = new FireFoxDriver();
driver.Navigate().GoToUrl("http://youwebsite");
ReadOnlyCollection<IWebElement> query
= driver.FindElements( By.XPath("//a") );
foreach(IWebElement hyperLink in query)
{
string locatorFormat = "//a[contains(#class,'{0}')][.='{1}']";
string locator = String.Format(locatorFormat,
hyperlink.GetAttribute("class"),
hyperlink.Value);
// spit out the locator for reference.
}
}
You're still going to need to associate the Locator to your code file, but this should at least get you started by extracting the locators for future use.
Here's an example of crawling links using Selenium 1.0 http://devio.wordpress.com/2008/10/24/crawling-all-links-with-selenium-and-nunit/
Selenium runs on browser side, even if you can grab all the elements, there is no way to save it in a file. As I know , Selenium is not design for that kinds of work.
You need to get the entire source of the page? if so, try the GetHtmlSource method
http://release.seleniumhq.org/selenium-remote-control/0.9.0/doc/dotnet/html/Selenium.DefaultSelenium.GetHtmlSource.html