blob: 2bf087b4699e97df58e6988e2c0eeb22e249d128 [file] [log] [blame]
// <copyright file="LoadableComponent{T}.cs" company="Selenium Committers">
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// </copyright>
namespace OpenQA.Selenium.Support.UI;
/// <summary>
/// <para>Represents any abstraction of something that can be loaded.</para>
/// <para>This may be an entire web page, or simply a component within that page (such as a login box or menu) or even a service.</para>
/// <para>
/// <code>
/// // Example usage:
/// new MyComponent().Load();
/// </code>
/// </para>
/// </summary>
/// <typeparam name="T">The type to be returned (normally the subclass' type)</typeparam>
/// <remarks>
/// <para>After the <see cref="Load()"/> method is called, the component will be loaded and ready for use.</para>
/// <para>Overload the protected Load and IsLoaded members to both load a component and determine if the component is already loaded.</para>
/// </remarks>
public abstract class LoadableComponent<T> : ILoadableComponent
where T : LoadableComponent<T>
{
/// <summary>
/// Gets or sets the message for the exception thrown when a component cannot be loaded
/// </summary>
public virtual string? UnableToLoadMessage { get; set; }
/// <summary>
/// Gets a value indicating whether the component is fully loaded.
/// </summary>
/// <remarks>
/// When the component is loaded, this property will return true or false depending on
/// the execution of <see cref="EvaluateLoadedStatus"/> to indicate the not loaded state.
/// </remarks>
protected bool IsLoaded
{
get
{
try
{
return this.EvaluateLoadedStatus();
}
catch (WebDriverException)
{
return false;
}
}
}
/// <summary>
/// Ensure that the component is currently loaded.
/// </summary>
/// <returns>The loaded component.</returns>
/// <remarks>This is equivalent to the Get() method in Java version.</remarks>
public virtual T Load()
{
if (this.IsLoaded)
{
return (T)this;
}
else
{
this.TryLoad();
}
if (!this.IsLoaded)
{
throw new LoadableComponentException(this.UnableToLoadMessage);
}
return (T)this;
}
/// <summary>
/// Ensure that the component is currently loaded.
/// </summary>
/// <returns>The loaded <see cref="ILoadableComponent"/> instance.</returns>
ILoadableComponent ILoadableComponent.Load()
{
return (ILoadableComponent)this.Load();
}
/// <summary>
/// HandleLoadError gives a subclass the opportunity to handle a <see cref="WebDriverException"/> that occurred
/// during the execution of <see cref="ExecuteLoad"/>.
/// </summary>
/// <param name="ex">The exception which occurs on load.</param>
protected virtual void HandleLoadError(WebDriverException ex)
{
}
/// <summary>
/// When this method returns, the component modeled by the subclass should be fully loaded. This
/// subclass is expected to navigate to an appropriate page or trigger loading the correct HTML
/// should this be necessary.
/// </summary>
protected abstract void ExecuteLoad();
/// <summary>
/// Determine whether or not the component is loaded. Subclasses are expected to provide the details
/// to determine if the page or component is loaded.
/// </summary>
/// <returns>A boolean value indicating if the component is loaded.</returns>
protected abstract bool EvaluateLoadedStatus();
/// <summary>
/// Attempts to load this component, providing an opportunity for the user to handle any errors encountered
/// during the load process.
/// </summary>
/// <returns>A self-reference to this <see cref="LoadableComponent{T}"/></returns>
protected T TryLoad()
{
try
{
this.ExecuteLoad();
}
catch (WebDriverException e)
{
this.HandleLoadError(e);
}
return (T)this;
}
}