Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 0 additions & 24 deletions CSF.Screenplay.Abstractions/Performables/IProvidesTimeSpan.cs

This file was deleted.

30 changes: 0 additions & 30 deletions CSF.Screenplay.Abstractions/Performables/TimeSpanBuilder.cs

This file was deleted.

146 changes: 0 additions & 146 deletions CSF.Screenplay.Abstractions/Performables/TimeSpanBuilder.generic.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
Screenplay ships [with a small number of Abilities and performables] but it is designed to be extended with new ones.
New [Abilities], [Actions] and [Questions] extend [Screenplay] by allowing [Actors] to interact with new APIs, services and libraries.

Broadly-speaking to extend Screenplay in this way you must:
Broadly-speaking, to extend Screenplay in this way you must:

* Write one or more new ability types which provide access to the API of the service or library with which you'd like to interact
* Write one or more Action and/or Question [Performables] which make use of that ability

[with a small number of Abilities and performables]: ../performables/index.md
[with a small number of Abilities and performables]: ../extensions/index.md#built-in-abilities-and-performables
[Screenplay]: xref:CSF.Screenplay.Screenplay

## Writing abilities

Recall that [Abilities] represent capabilities & dependencies granted to or associated with [Actors].
It is normal for developers to want to write new Ability classes in order to provide capabilities/dependencies which are not yet catered-for.
It is normal for developers to want to write new Ability classes in order to provide capabilities/dependencies which are not yet catered-for.

Ability classes do not _need to derive_ from any particular base type, although it is strongly recommended that they implement [`ICanReport`].
Ability classes [may constructor-inject dependencies] and should declare whatever API is appropriate.
Expand Down
26 changes: 24 additions & 2 deletions CSF.Screenplay.Docs/docs/extensions/index.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@
# Screenplay extensions

This page lists the officially-supported **[Screenplay Extensions]**.
Most of the useful functionality of Screenplay comes from **[Screenplay Extensions]**.
Extensions typically provide [Abilities], [Performables] and [Builders] which offer functionality relevant to that extension's technology.

[Screenplay Extensions]: ../../glossary/Extension.md
[Abilities]: ../../glossary/Ability.md
[Performables]: ../../glossary/Performable.md
[Builders]: ../builderPattern/index.md

## Officially-supported extensions

These extensions are authored and maintained alongside the main Screenplay library.
Developers are encouraged and welcomed to create their own extensions, too.

* **[Selenium](selenium/index.md)**: _remote control Web Browsers using Selenium Web Driver_
* **[Web APIs](webApis/index.md)**: _communicate with Web APIs with an HTTP Client_

[Screenplay Extensions]: ../../glossary/Extension.md
## Built-in abilities and performables

Screenplay offers a very small number of abilities and performables within the base library; these do not require the installation of an extension.

### Using a Stopwatch

When an actor needs to keep precise track of time, you may give them the [`UseAStopwatch`] ability.
Actors with this ability may use Actions and Questions which relate to use of the stopwatch.
These are all accessible from the builder class [`StopwatchBuilder`].

[`UseAStopwatch`]: xref:CSF.Screenplay.Abilities.UseAStopwatch
[`StopwatchBuilder`]: xref:CSF.Screenplay.Performables.StopwatchBuilder
24 changes: 0 additions & 24 deletions CSF.Screenplay.Docs/docs/performables/index.md

This file was deleted.

6 changes: 0 additions & 6 deletions CSF.Screenplay.Docs/docs/performables/toc.yml

This file was deleted.

2 changes: 0 additions & 2 deletions CSF.Screenplay.Docs/docs/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@
items:
- name: Assets
href: Assets.md
- name: Performables
href: performables/toc.yml
- name: Best practices
items:
- name: When to use for tests
Expand Down
5 changes: 3 additions & 2 deletions CSF.Screenplay.Docs/glossary/Extension.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ The Screenplay library doesn't do much on its own.
The packages CSF.Screenplay.Abstractions and CSF.Screenplay offer very little in the way of [Abilities], [Actions] or [Questions].
Since these are the building blocks for writing [Tasks] and [Performances], developers won't get very far without installing one or more extensions.

There are [a few extensions available] which are maintained by the authors of CSF.Screenplay.
A few extensions are authored and maintained alongside the CSF.Screenplay library.
These are listed on **[the extensions documentation page]**.

[Abilities]: Ability.md
[Actions]: Action.md
[Questions]: Question.md
[Tasks]: Task.md
[Performances]: xref:CSF.Screenplay.IPerformance
[a few extensions available]: ../docs/extensions/index.md
[the extensions documentation page]: ../docs/extensions/index.md

## Can't see what you need?

Expand Down
8 changes: 3 additions & 5 deletions Tests/CSF.Screenplay.NUnit.Tests/TestWithDescription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ public void SecondTest(IPerformance performance)

static void AssertThatPerformanceHasCorrectState(IPerformance performance, IdentifierAndName[] expectedNamingHierarchy)
{
Assert.Multiple(() =>
{
Assert.That(performance, Is.Not.Null, "Performance must not be null");
Assert.That(performance.NamingHierarchy, Is.EqualTo(expectedNamingHierarchy), "Performance naming hierarchy is correct");
});
using var scope = Assert.EnterMultipleScope();
Assert.That(performance, Is.Not.Null, "Performance must not be null");
Assert.That(performance.NamingHierarchy, Is.EqualTo(expectedNamingHierarchy), "Performance naming hierarchy is correct");
}
}
8 changes: 3 additions & 5 deletions Tests/CSF.Screenplay.NUnit.Tests/TestWithoutDescription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ public void SecondTest(IPerformance performance)

static void AssertThatPerformanceHasCorrectState(IPerformance performance, IdentifierAndName[] expectedNamingHierarchy)
{
Assert.Multiple(() =>
{
Assert.That(performance, Is.Not.Null, "Performance must not be null");
Assert.That(performance.NamingHierarchy, Is.EqualTo(expectedNamingHierarchy), "Performance naming hierarchy is correct");
});
using var scope = Assert.EnterMultipleScope();
Assert.That(performance, Is.Not.Null, "Performance must not be null");
Assert.That(performance.NamingHierarchy, Is.EqualTo(expectedNamingHierarchy), "Performance naming hierarchy is correct");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,18 @@ public void UnsupportedFunctionalityShouldThrowNotSupportedException()
var container = new ObjectContainer();
var sut = new ServiceCollectionAdapter(container);

Assert.Multiple(() =>
{
Assert.That(() => sut[0], Throws.InstanceOf<NotSupportedException>(), "Indexer get");
Assert.That(() => sut[0] = null, Throws.InstanceOf<NotSupportedException>(), "Indexer set");
Assert.That(() => sut.Clear(), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.Clear));
Assert.That(() => sut.Contains(null), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.Contains));
Assert.That(() => sut.CopyTo(null, default), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.CopyTo));
Assert.That(() => sut.GetEnumerator(), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.GetEnumerator));
Assert.That(() => ((IEnumerable) sut).GetEnumerator(), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.GetEnumerator) + ": " + nameof(IEnumerable));
Assert.That(() => sut.IndexOf(default), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.IndexOf));
Assert.That(() => sut.Insert(default, null), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.Insert));
Assert.That(() => sut.Remove(null), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.Remove));
Assert.That(() => sut.RemoveAt(default), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.RemoveAt));
});
using var scope = Assert.EnterMultipleScope();
Assert.That(() => sut[0], Throws.InstanceOf<NotSupportedException>(), "Indexer get");
Assert.That(() => sut[0] = null, Throws.InstanceOf<NotSupportedException>(), "Indexer set");
Assert.That(() => sut.Clear(), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.Clear));
Assert.That(() => sut.Contains(null), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.Contains));
Assert.That(() => sut.CopyTo(null, default), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.CopyTo));
Assert.That(() => sut.GetEnumerator(), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.GetEnumerator));
Assert.That(() => ((IEnumerable) sut).GetEnumerator(), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.GetEnumerator) + ": " + nameof(IEnumerable));
Assert.That(() => sut.IndexOf(default), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.IndexOf));
Assert.That(() => sut.Insert(default, null), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.Insert));
Assert.That(() => sut.Remove(null), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.Remove));
Assert.That(() => sut.RemoveAt(default), Throws.InstanceOf<NotSupportedException>(), nameof(IServiceCollection.RemoveAt));
}

[Test]
Expand Down
Loading
Loading