пятница, 15 ноября 2013 г.

3.0.5 Code duplication


JS:  +2783 lines -175 dup lines (-6.29%), 19.74% overall (-0.79%)
CS: +82 lines -12 dup lines (-14.63%), 5.09% overal (-0.01%)



The most significant added JS duplication:

Found 22 duplicate lines in the following files:
 Between lines 128 and 152 in D:\src\trunk\Utilities\..\Code\Main\Tp.Web\JavaScript\tau\scripts\tau\ui\templates\list_\grid.entity\ui.template.list.grid.entity.row.js
 Between lines 65 and 90 in D:\src\trunk\Utilities\..\Code\Main\Tp.Web\JavaScript\tau\scripts\tau\ui\templates\list_\grid.entity\testplanrun\ui.template.list.grid.entity.row.testcaserun.js
 Between lines 90 and 114 in D:\src\trunk\Utilities\..\Code\Main\Tp.Web\JavaScript\tau\scripts\tau\ui\templates\list_\grid.entity\testplan\ui.template.list.grid.entity.row.testplanrun.js




https://docs.google.com/spreadsheet/ccc?key=0ArF9ExjGEio4dENPWXVpTUdNTTc4RGRHWVBQOG9mZHc&usp=sharing

пятница, 23 августа 2013 г.

Git Extensions + Hub flow + Git

Here is some tips how to somehow integrate GitHub and Hubflow to Git Extensions:

Git Extensions supports scripting, that could be integrated either in UI or autostart before/after some actions.

I've created the following scripts for Git Extension, hope they will be useful:

Flow feature start, create pull request and prune remote branches:

To add these scripts go to Settings->Settings->Scripts:

  1. Prune remote - git / remote prune origin
  2. HF Feature start - git / hf feature start {UserInput} - it will ask for feature name
  3. Create pull requests - git / hub pull-request -b TargetProcess:develop -h TargetProcess:{cLocalBranch}

For pull requests you need to download a hub extension for git from here and put in your Git\Bin folder. It just nothing than a https://github.com/github/hub script. As far as git bash we are using could not start the hub script directly, I've just renamed it to git-hub to allow run it as standard git command, i.e. git hub pull-request.

пятница, 7 октября 2011 г.

Freedom of Functional Tests

Looking at our functional tests (FTs) we can highlight several problems:

  • Synchronization code here like WaitFor is everywhere.
[When("opened Find Duplicate popup")]
public void OpenFindDuplicatePopup()
{
	Context.SeleniumInstance.Click("//a[.='Find Duplicate']");
	Synchronizer.WaitForAjax();
}

[When("wait for page to load")]
public void WaitForPageToLoad()
{
	Context.SeleniumInstance.WaitForPageToLoad(Config.WaitForPageToLoad);
	Synchronizer.WaitForAjax();
}
[When("clicked on Mark as Duplicate button")]
public void ClickMarkAsDuplicate()
{
	Context.SeleniumInstance.Click("//button[.='Mark as Duplicate']");
	Synchronizer.WaitForAjax();
}

  • xpaths everywhere, and not many of them shared.
  • We also depend on page structure while looking for web element heavily
  • Dependency on TP database.
    As our FTs depends on direct connection to database it prevents us to run them against any instance of TP and share tests with plugin developers from other companies.
  • Contexts (AKA testing environment like 'create a project for a process, put user stories and assign a user then proceed') are not defined and not shared across all FTs
For now agreed on following decisions:

Synchronization code here like WaitFor is everywhere
&&
xpaths everywhere, and not many of them shared.

The solution is simple: heavily use PageObject pattern.
The rule regarding xpath:

Don't use xpath.
We should rather use css selectors as they are much more stable to page structure changes. Css selectors used for testing should start with _ prefix

public IWebElement FirstNameInput
{
	get { return _browser.FindElement(By.CssSelector("input._firstName")); }
}

Page Objects design rules:
  • Page Object should be always created via DI container (structure map in our case). This will make our code more flexible in the matter of changes

The you can revise the following articles regarding best practices DI usage:


Poor-Man DI Antipattern Description

Dependency on TP database

Use REST to perform quick manipulation of Target Process site.


Contexts

Different tests may use the same contexts in the matter of system under test (SUT) test.

Some of tests may use slightly different contexts.



It is necessary to provide a possibility to reuse contexts or their parts across the FTs.




Context Architecture





Whole Picture for new-style FTs



















среда, 14 сентября 2011 г.

Subversion Plugin Mashups now are running by CI server

For a long time we have many mashups javascript unit tests implemented.

Until now they were runnable by hand only, but it's not an option.

There is a MashupSpecs C# unit test introduced today into Tp.Subversion.Tests.

It's written in C# with using of WebDriver. It opens a web page with javascript unit tests, then gathers results. If any errors acquired then it will fail the build.

Now it's quite simple implementation and may be improved:

[TestFixture]
	public class MashupSpecs
	{
		private IWebDriver _webDriver;
 
		[SetUp]
		public void Init()
		{
			_webDriver = new RemoteWebDriver(DesiredCapabilities.Firefox());
			_webDriver.Navigate().GoToUrl(string.Format(@"file:///{0}/UI/Tests/index.html"AppDomain.CurrentDomain.BaseDirectory));
		}
 
		[TearDown]
		public void Destroy()
		{
			_webDriver.Close();
			_webDriver.Dispose();
		}
 
		[Test]
		public void ShouldRunAllTests()
		{
			new WebDriverWait(_webDriverTimeSpan.FromSeconds(10)).Until(x => x.FindElement(By.Id("qunit-banner")).GetAttribute("class") != string.Empty);
			var failedTests = _webDriver.FindElements(By.CssSelector("#qunit-tests>.fail"));
			failedTests.Should(Be.Emptynew FailedTestCollection(failedTests).ToString());
		}
	}
 
	public class FailedTestCollection : ReadOnlyCollection<IWebElement>
	{
		public FailedTestCollection(IList<IWebElement> list)
			: base(list) {}
 
		public override string ToString()
		{
			var result = new StringBuilder();
			foreach (var webElement in Items)
			{
				result.AppendLine(webElement.Text);
				result.AppendLine();
			}
			return result.ToString();
		}
	}


среда, 31 августа 2011 г.

Unicode support in NSIS

To support Unicode TP installer has been updated to Unicode NSIS v.2.46-1. Here is how to start using new version:

1. Install it. New installer can be found in the same trunk/Utilities/NSIS folder as the old one. After installation copy the contents of trunk/Utilities/NSIS/NSIS folder (i.e. Include and Plugins folders) to the directory where NSIS has been installed (most probably c:\Program Files(x86)\NSIS). Do not forget to update Path variable for NSIS if necessary.

2. Convert NSI-scripts to Unicode. Usually, all that needs to be done to convert old installation scripts to Unicode NSIS is convert the NSI script file from an ANSI text file to a UTF-16LE file or as of 2.42.3, UTF-8 file.

3. Update NSIS plugins. Newer versions of some plugins (such as AccessControl, OLEDB, some others) provide Unicode support so you won't have to make any changes in the way these plugins are used.

4. Update NSIS scripts if necessary. If some plugins don't have Unicode version then CallANSIPlugin.nsh (can be found in trunk/Utilities/NSIS/NSIS/Include) will help you: use PushAsANSI, PushAsUTF8, PopAsANSI, PopAsUTF8 to convert string arguments before passing them to and after retrieving result from a macros/function. If you are using System plugin make sure that you are not calling the ANSI specific Win32 API. Most such API end with the letter A, for example: MessageBoxA(). Such API should either be converted to the tchar version such as MessageBox() or the wide-char version such as MessageBoxW().

And that's it.



среда, 10 августа 2011 г.

DateTime and JavaScritSerializer

Hi, all!

Let me show you a small unit test

1 [Test]
2 public void ShouldSerializeDateCorrectly()
3 {
4 var date = new DateTime(2011, 8, 8);
5 var serialized = new JavaScriptSerializer().Serialize(date);
6 var deserialized = new JavaScriptSerializer().Deserialize<DateTime>(serialized);
7 Assert.That(deserialized, Is.EqualTo(date));
8 }


How do you think it will behave? I'll surprise you: it fails.

The reason of such a strange behavior is described here. The main point is that deserialization assumes the value is serialized using GMT time.

Ok, that's funny, but how exactly it can affect TargetProcess? We're moving to REST little by little, but there are still many places where client javascript code communicates with TP server through web services using the power of ScriptServiceAttribute. Guess how the data passed to server is deserialized?

So, please be careful when accessing DateTime objects passed from client javascript and don't forget to convert it to local time as I would do to make my test pass.

1 [Test]
2 public void ShouldSerializeDateCorrectly()
3 {
4 var date = new DateTime(2011, 8, 8);
5 var serialized = new JavaScriptSerializer().Serialize(date);
6 var deserialized = new JavaScriptSerializer().Deserialize<DateTime>(serialized);
7 Assert.That(deserialized.ToLocalTime(), Is.EqualTo(date));
8 }
9