/// <summary>
        /// Find a page object in the page object tree.
        /// </summary>
        /// <param name="condition">The condition that must evaluate true for the resulting page object.</param>
        /// <param name="result">The result page object.</param>
        /// <typeparam name="TPageObject">The page object type to search for.</typeparam>
        /// <returns>The page object.</returns>
        private bool TryFind <TPageObject>(Predicate <TPageObject> condition, out TPageObject result) where TPageObject : IPageObject
        {
            Queue <IPageObject> q = new Queue <IPageObject>();

            IEnumerable <TPageObject> registeredObjects;

            if (TryGet(out registeredObjects))
            {
                foreach (var a in registeredObjects)
                {
                    q.Enqueue(a);
                }
            }

            q.Enqueue(rootObject);

            while (q.Count > 0)
            {
                IPageObject current = q.Dequeue();

                // interface types match any implementation, whereas classes must match exactly
                var match = typeof(TPageObject).IsInterface ? current is TPageObject : current.GetType().Equals(typeof(TPageObject));
                if (match)
                {
                    TPageObject page = (TPageObject)current;
                    Register <TPageObject>(page);

                    if ((page as IPageObjectInternal).OnCondition && condition(page))
                    {
                        var parent = (IPageObject)page.Parent;
                        result = parent == null ? page : (TPageObject)(Activator.CreateInstance(page.GetType()) as IUIObjectInternal).Init(parent);
                        return(true);
                    }
                }

                // traverse children
                foreach (IPageObject childPageObject in current.Children <TPageObject>())
                {
                    // generic page object must be child-less
                    if (current.GetType().IsGenericType)
                    {
                        Trace.TraceInformation("Ignoring children of generic page object type <" + current.GetType().Name + ">");
                        continue;
                    }

                    q.Enqueue(childPageObject);
                }
            }

            result = default(TPageObject);
            return(false);
        }
        /// <summary>
        /// Run all tests with the <c>PageTestAttribute</c>.
        /// </summary>
        /// <param name="source">The source page object.</param>
        /// <param name="pageObjectStatistics">Whether to write the result tree.</param>
        /// <param name="filter">The test method filter predicate.</param>
        /// <param name="writeTree">Whether to write the result tree.</param>
        /// <returns>This page object.</returns>
        private static Tree TestBottomUp(this IPageObject source, Func <MethodInfo, Type, bool> filter, bool writeTree, PageObjectStatistics pageObjectStatistics)
        {
            Trace.WriteLine($"Run tests for {source.GetType().FullName}");

            // run tests for every child
            foreach (var child in source.Children())
            {
                TestBottomUp(child, filter, false, pageObjectStatistics);
            }

            // run tests for this page object
            return(Test(source, filter, writeTree, pageObjectStatistics));
        }
        /// <summary>
        /// Run all tests with the <c>PageTestAttribute</c>.
        /// </summary>
        /// <param name="source">The source page object.</param>
        /// <param name="methodFilter">The test method filter predicate.</param>
        /// <param name="pageTestClassFilter">The page test class filter predicate.</param>
        /// <returns>This page object.</returns>
        public static IPageObject TestBottomUp(this IPageObject source, Predicate <MethodInfo> methodFilter = null, Predicate <IPageObjectTests> pageTestClassFilter = null)
        {
            Trace.WriteLine("Run tests for " + source.GetType().FullName);

            // run tests for every child
            foreach (var child in source.Children())
            {
                child.TestBottomUp(methodFilter, pageTestClassFilter);
            }

            // run tests for this page object
            source.Test(methodFilter, pageTestClassFilter);

            return(source);
        }