Skip to content

Commit c56984f

Browse files
feat: Add Playwright module (#1288)
Co-authored-by: Andre Hofmeister <[email protected]>
1 parent a652a9e commit c56984f

File tree

16 files changed

+367
-0
lines changed

16 files changed

+367
-0
lines changed

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.32.1"/>
6969
<PackageVersion Include="Microsoft.Azure.Kusto.Data" Version="12.2.8"/>
7070
<PackageVersion Include="Microsoft.Data.SqlClient" Version="5.2.2"/>
71+
<PackageVersion Include="Microsoft.Playwright" Version="1.55.0"/>
7172
<PackageVersion Include="Milvus.Client" Version="2.2.2-preview.6"/>
7273
<PackageVersion Include="MongoDB.Driver" Version="3.2.0"/>
7374
<PackageVersion Include="MyCouch" Version="7.6.0"/>

Testcontainers.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Oracle", "sr
102102
EndProject
103103
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Papercut", "src\Testcontainers.Papercut\Testcontainers.Papercut.csproj", "{B2608563-8EE4-49AA-A9A0-B1614486AEEF}"
104104
EndProject
105+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Playwright", "src\Testcontainers.Playwright\Testcontainers.Playwright.csproj", "{7F91A202-4F07-470D-881C-9A46A700DCA5}"
106+
EndProject
105107
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.PostgreSql", "src\Testcontainers.PostgreSql\Testcontainers.PostgreSql.csproj", "{8AB91636-9055-4900-A72A-7CFFACDFDBF0}"
106108
EndProject
107109
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.PubSub", "src\Testcontainers.PubSub\Testcontainers.PubSub.csproj", "{E6642255-667D-476B-B584-089AA5E6C0B1}"
@@ -230,6 +232,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Platform.Lin
230232
EndProject
231233
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Platform.Windows.Tests", "tests\Testcontainers.Platform.Windows.Tests\Testcontainers.Platform.Windows.Tests.csproj", "{3E55CBE8-AFE8-426D-9470-49D63CD1051C}"
232234
EndProject
235+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Playwright.Tests", "tests\Testcontainers.Playwright.Tests\Testcontainers.Playwright.Tests.csproj", "{DE065875-1B7B-4E20-9332-C88C8437333D}"
236+
EndProject
233237
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.PostgreSql.Tests", "tests\Testcontainers.PostgreSql.Tests\Testcontainers.PostgreSql.Tests.csproj", "{56D0DCA5-567F-4B3B-8B79-CB108F8EB8A6}"
234238
EndProject
235239
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.PubSub.Tests", "tests\Testcontainers.PubSub.Tests\Testcontainers.PubSub.Tests.csproj", "{0F86BCE8-62E1-4BFC-AA84-63C7514C90AC}"
@@ -434,6 +438,10 @@ Global
434438
{B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
435439
{B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
436440
{B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Release|Any CPU.Build.0 = Release|Any CPU
441+
{7F91A202-4F07-470D-881C-9A46A700DCA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
442+
{7F91A202-4F07-470D-881C-9A46A700DCA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
443+
{7F91A202-4F07-470D-881C-9A46A700DCA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
444+
{7F91A202-4F07-470D-881C-9A46A700DCA5}.Release|Any CPU.Build.0 = Release|Any CPU
437445
{8AB91636-9055-4900-A72A-7CFFACDFDBF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
438446
{8AB91636-9055-4900-A72A-7CFFACDFDBF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
439447
{8AB91636-9055-4900-A72A-7CFFACDFDBF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -690,6 +698,10 @@ Global
690698
{3E55CBE8-AFE8-426D-9470-49D63CD1051C}.Debug|Any CPU.Build.0 = Debug|Any CPU
691699
{3E55CBE8-AFE8-426D-9470-49D63CD1051C}.Release|Any CPU.ActiveCfg = Release|Any CPU
692700
{3E55CBE8-AFE8-426D-9470-49D63CD1051C}.Release|Any CPU.Build.0 = Release|Any CPU
701+
{DE065875-1B7B-4E20-9332-C88C8437333D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
702+
{DE065875-1B7B-4E20-9332-C88C8437333D}.Debug|Any CPU.Build.0 = Debug|Any CPU
703+
{DE065875-1B7B-4E20-9332-C88C8437333D}.Release|Any CPU.ActiveCfg = Release|Any CPU
704+
{DE065875-1B7B-4E20-9332-C88C8437333D}.Release|Any CPU.Build.0 = Release|Any CPU
693705
{56D0DCA5-567F-4B3B-8B79-CB108F8EB8A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
694706
{56D0DCA5-567F-4B3B-8B79-CB108F8EB8A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
695707
{56D0DCA5-567F-4B3B-8B79-CB108F8EB8A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -805,6 +817,7 @@ Global
805817
{49051DBC-6B80-4412-8505-BC2764A877BD} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
806818
{596EAFC1-0496-495C-B382-D57415FA456A} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
807819
{B2608563-8EE4-49AA-A9A0-B1614486AEEF} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
820+
{7F91A202-4F07-470D-881C-9A46A700DCA5} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
808821
{8AB91636-9055-4900-A72A-7CFFACDFDBF0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
809822
{E6642255-667D-476B-B584-089AA5E6C0B1} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
810823
{27D46863-65B9-4934-B3C8-2383B217A477} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
@@ -869,6 +882,7 @@ Global
869882
{F03FA970-BE2B-4AE2-96FE-7E1F805CEA20} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
870883
{DA1D7ADE-452C-4369-83CC-56289176EACD} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
871884
{3E55CBE8-AFE8-426D-9470-49D63CD1051C} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
885+
{DE065875-1B7B-4E20-9332-C88C8437333D} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
872886
{56D0DCA5-567F-4B3B-8B79-CB108F8EB8A6} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
873887
{0F86BCE8-62E1-4BFC-AA84-63C7514C90AC} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
874888
{D05FCB31-793E-43E0-BD6C-077013AE9113} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}

docs/modules/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ await moduleNameContainer.StartAsync();
6060
| OpenSearch | `opensearchproject/opensearch:2.12.0` | [NuGet](https://www.nuget.org/packages/Testcontainers.OpenSearch) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.OpenSearch) |
6161
| Oracle | `gvenzl/oracle-xe:21.3.0-slim-faststart` | [NuGet](https://www.nuget.org/packages/Testcontainers.Oracle) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Oracle) |
6262
| Papercut | `changemakerstudiosus/papercut-smtp:latest` | [NuGet](https://www.nuget.org/packages/Testcontainers.Papercut) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Papercut) |
63+
| Playwright | `mcr.microsoft.com/playwright:v1.55.1` | [NuGet](https://www.nuget.org/packages/Testcontainers.Playwright) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Playwright) |
6364
| PostgreSQL | `postgres:15.1` | [NuGet](https://www.nuget.org/packages/Testcontainers.PostgreSql) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.PostgreSql) |
6465
| PubSub | `gcr.io/google.com/cloudsdktool/google-cloud-cli:446.0.1-emulators` | [NuGet](https://www.nuget.org/packages/Testcontainers.PubSub) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.PubSub) |
6566
| Pulsar | `apachepulsar/pulsar:3.0.6` | [NuGet](https://www.nuget.org/packages/Testcontainers.Pulsar) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Pulsar) |

docs/modules/playwright.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Playwright
2+
3+
[Playwright](https://playwright.dev/) is a framework for web testing and automation. It allows testing across all modern rendering engines including Chromium, WebKit, and Firefox with a single API. This module provides pre-configured browser containers for automated testing.
4+
5+
Add the following dependency to your project file:
6+
7+
```shell title="NuGet"
8+
dotnet add package Testcontainers.Playwright
9+
```
10+
11+
You can start a Playwright container instance from any .NET application. To create and start a container instance with the default configuration, use the module-specific builder as shown below:
12+
13+
=== "Start a Playwright container"
14+
```csharp
15+
var playwrightContainer = new PlaywrightBuilder().Build();
16+
await playwrightContainer.StartAsync();
17+
```
18+
19+
This example uses xUnit.net's `IAsyncLifetime` interface to manage the lifecycle of the container. The container is started in the `InitializeAsync` method before the test method runs, ensuring that the environment is ready for testing. After the test completes, the container is removed in the `DisposeAsync` method.
20+
21+
This example demonstrates the Playwright container accessing a web site running inside another container (using the [`testcontainers/helloworld`](https://github.com/testcontainers/helloworld) image). Both containers are assigned to a shared network (see the [Network configuration](#network-configuration) section) to enable communication between them.
22+
23+
=== "Usage Example"
24+
```csharp
25+
--8<-- "tests/Testcontainers.Playwright.Tests/PlaywrightContainerTest.cs:UsePlaywrightContainer"
26+
```
27+
28+
The test example uses the following NuGet dependencies:
29+
30+
=== "Package References"
31+
```xml
32+
--8<-- "tests/Testcontainers.Playwright.Tests/Testcontainers.Playwright.Tests.csproj:PackageReferences"
33+
```
34+
35+
To execute the tests, use the command `dotnet test` from a terminal.
36+
37+
--8<-- "docs/modules/_call_out_test_projects.txt"
38+
39+
## Network configuration
40+
41+
The Playwright container is configured with a network that can be shared with other containers. This is useful when testing applications that need to communicate with other services. Use the `GetNetwork()` method to access the container's network:
42+
43+
```csharp
44+
var helloWorldContainer = new ContainerBuilder()
45+
.WithNetwork(playwrightContainer.GetNetwork())
46+
.Build();
47+
```

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ nav:
6060
- modules/mssql.md
6161
- modules/neo4j.md
6262
- modules/opensearch.md
63+
- modules/playwright.md
6364
- modules/postgres.md
6465
- modules/qdrant.md
6566
- modules/rabbitmq.md
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
root = true
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
namespace Testcontainers.Playwright;
2+
3+
/// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
4+
[PublicAPI]
5+
public sealed class PlaywrightBuilder : ContainerBuilder<PlaywrightBuilder, PlaywrightContainer, PlaywrightConfiguration>
6+
{
7+
public const string PlaywrightNetworkAlias = "standalone-container";
8+
9+
public const string PlaywrightImage = "mcr.microsoft.com/playwright:v1.55.1";
10+
11+
public const ushort PlaywrightPort = 8080;
12+
13+
/// <summary>
14+
/// Initializes a new instance of the <see cref="PlaywrightBuilder" /> class.
15+
/// </summary>
16+
public PlaywrightBuilder()
17+
: this(new PlaywrightConfiguration())
18+
{
19+
DockerResourceConfiguration = Init().DockerResourceConfiguration;
20+
}
21+
22+
/// <summary>
23+
/// Initializes a new instance of the <see cref="PlaywrightBuilder" /> class.
24+
/// </summary>
25+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
26+
private PlaywrightBuilder(PlaywrightConfiguration resourceConfiguration)
27+
: base(resourceConfiguration)
28+
{
29+
DockerResourceConfiguration = resourceConfiguration;
30+
}
31+
32+
/// <inheritdoc />
33+
protected override PlaywrightConfiguration DockerResourceConfiguration { get; }
34+
35+
/// <inheritdoc />
36+
public override PlaywrightContainer Build()
37+
{
38+
Validate();
39+
return new PlaywrightContainer(DockerResourceConfiguration);
40+
}
41+
42+
/// <inheritdoc />
43+
protected override PlaywrightBuilder Init()
44+
{
45+
return base.Init()
46+
.WithImage(PlaywrightImage)
47+
.WithNetwork(new NetworkBuilder().Build())
48+
.WithNetworkAliases(PlaywrightNetworkAlias)
49+
.WithPortBinding(PlaywrightPort, true)
50+
.WithEntrypoint("/bin/sh", "-c")
51+
// Extract the Playwright version from the container at startup.
52+
.WithCommand("npx -y playwright@$(sed --quiet 's/.*\\\"driverVersion\\\": *\"\\([^\"]*\\)\".*/\\1/p' ms-playwright/.docker-info) run-server --port " + PlaywrightPort)
53+
.WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("Listening on ws://localhost:8080/"));
54+
}
55+
56+
/// <inheritdoc />
57+
protected override PlaywrightBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
58+
{
59+
return Merge(DockerResourceConfiguration, new PlaywrightConfiguration(resourceConfiguration));
60+
}
61+
62+
/// <inheritdoc />
63+
protected override PlaywrightBuilder Clone(IContainerConfiguration resourceConfiguration)
64+
{
65+
return Merge(DockerResourceConfiguration, new PlaywrightConfiguration(resourceConfiguration));
66+
}
67+
68+
/// <inheritdoc />
69+
protected override PlaywrightBuilder Merge(PlaywrightConfiguration oldValue, PlaywrightConfiguration newValue)
70+
{
71+
return new PlaywrightBuilder(new PlaywrightConfiguration(oldValue, newValue));
72+
}
73+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
namespace Testcontainers.Playwright;
2+
3+
/// <inheritdoc cref="ContainerConfiguration" />
4+
[PublicAPI]
5+
public sealed class PlaywrightConfiguration : ContainerConfiguration
6+
{
7+
/// <summary>
8+
/// Initializes a new instance of the <see cref="PlaywrightConfiguration" /> class.
9+
/// </summary>
10+
public PlaywrightConfiguration()
11+
{
12+
}
13+
14+
/// <summary>
15+
/// Initializes a new instance of the <see cref="PlaywrightConfiguration" /> class.
16+
/// </summary>
17+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
18+
public PlaywrightConfiguration(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
19+
: base(resourceConfiguration)
20+
{
21+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
22+
}
23+
24+
/// <summary>
25+
/// Initializes a new instance of the <see cref="PlaywrightConfiguration" /> class.
26+
/// </summary>
27+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
28+
public PlaywrightConfiguration(IContainerConfiguration resourceConfiguration)
29+
: base(resourceConfiguration)
30+
{
31+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
32+
}
33+
34+
/// <summary>
35+
/// Initializes a new instance of the <see cref="PlaywrightConfiguration" /> class.
36+
/// </summary>
37+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
38+
public PlaywrightConfiguration(PlaywrightConfiguration resourceConfiguration)
39+
: this(new PlaywrightConfiguration(), resourceConfiguration)
40+
{
41+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
42+
}
43+
44+
/// <summary>
45+
/// Initializes a new instance of the <see cref="PlaywrightConfiguration" /> class.
46+
/// </summary>
47+
/// <param name="oldValue">The old Docker resource configuration.</param>
48+
/// <param name="newValue">The new Docker resource configuration.</param>
49+
public PlaywrightConfiguration(PlaywrightConfiguration oldValue, PlaywrightConfiguration newValue)
50+
: base(oldValue, newValue)
51+
{
52+
}
53+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
namespace Testcontainers.Playwright;
2+
3+
/// <inheritdoc cref="DockerContainer" />
4+
[PublicAPI]
5+
public sealed class PlaywrightContainer : DockerContainer
6+
{
7+
private readonly PlaywrightConfiguration _configuration;
8+
9+
/// <summary>
10+
/// Initializes a new instance of the <see cref="PlaywrightContainer" /> class.
11+
/// </summary>
12+
/// <param name="configuration">The container configuration.</param>
13+
public PlaywrightContainer(PlaywrightConfiguration configuration)
14+
: base(configuration)
15+
{
16+
_configuration = configuration;
17+
}
18+
19+
/// <summary>
20+
/// Gets the Playwright connection string.
21+
/// </summary>
22+
/// <returns>The Playwright connection string.</returns>
23+
public string GetConnectionString()
24+
{
25+
return new UriBuilder("ws", Hostname, GetMappedPublicPort(PlaywrightBuilder.PlaywrightPort)).ToString();
26+
}
27+
28+
/// <summary>
29+
/// Gets the Playwright network.
30+
/// </summary>
31+
/// <returns>The Playwright network.</returns>
32+
public INetwork GetNetwork()
33+
{
34+
return _configuration.Networks.Single();
35+
}
36+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFrameworks>net8.0;net9.0;netstandard2.0;netstandard2.1</TargetFrameworks>
4+
<LangVersion>latest</LangVersion>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<PackageReference Include="JetBrains.Annotations" VersionOverride="2023.3.0" PrivateAssets="All"/>
8+
</ItemGroup>
9+
<ItemGroup>
10+
<ProjectReference Include="../Testcontainers/Testcontainers.csproj"/>
11+
</ItemGroup>
12+
</Project>

0 commit comments

Comments
 (0)