I am planning to use Playwright .NET to perform automated UI testing in a C# dotnet project. The issue is that I would like to have global configuration that can be set rather than needing to define the same settings repeatedly in the context of each test, but I cannot seem to find any working examples.
The documentation at playwright.dev implies that I should be able to simply include a "playwright.config.js" file at the root of the project, but no clear definition of what the content of that file should be. I have experimented with the example provided for Playwright Node.js, using:
import { PlaywrightTestConfig } from '#playwright/test';
const config: PlaywrightTestConfig = {
use: {
// Browser options
headless: false,
slowMo: 50,
// Context options
viewport: { width: 1280, height: 720 },
ignoreHTTPSErrors: true,
// Artifacts
screenshot: 'only-on-failure',
//video: 'retry-with-video',
},
outputDir: "C:\\stuff\\screenshots",
preserverOutput: 'always',
quiet: false,
};
export default config;
However, these settings do not seem to be applied and there is no indication that the playwright.config.js file is either loading or failing.
Any help or a simple example to get me pointed in the right direction would be much appreciated.
LaunchAsync expects a BrowserTypeLaunchOptions class. You could have that object serialized in a JSON file, parse it and pass that options instance as an argument.
Related
This is both a question and an answer. I've fixed my problem, but it seems a bit wrong.
My original problem is running my asp.net core integration tests in a bitbucket pipeline causes System.IO.IOException: The configured user limit (128) on the number of inotify instances has been reached. Some solutions call for changing some setting through sysctl, but that is restricted by bitbucket, so that isn't an option for me.
The second way of fixing this, as noted in these stackoverflow answers, is to turn reloadOnChange off.
My new problem is now, how do we best do this for the test WebApplicationFactory?
One solution that has worked for me, which is the least amount of code, seems like a total hack. I iterate through all the JsonConfigurationSource and set ReloadOnChange to false.
Full solution:
public class TestApplicationFactory : WebApplicationFactory<Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration(config =>
{
foreach (var source in config.Sources)
{
if (source is JsonConfigurationSource)
{
var jsonConfigSource = (JsonConfigurationSource) source;
jsonConfigSource.ReloadOnChange = false;
}
}
});
}
}
Another solution, that I haven't tried, may be to override CreateWebHostBuilder(). However, it seems like more code and a lot of copy and paste from the default one.
Am I missing something? Is there a better way to do this?
Just experienced this issue myself running integration tests within a Linux container and followed the previous suggestions to switch off the ReloadOnChange within the WebApplicationFactory. Unfortunately that did not resolve the problem and integration tests were still failing with the same error:
System.IO.IOException: The configured user limit (128) on the number of inotify instances has been reached.
I also tried to configure xUnit to run the integration tests sequentially rather than in parallel, but that did not work either.
The solution that did work for me was to set the appropriate environment variable within the container that runs the integration tests:
export ASPNETCORE_hostBuilder__reloadConfigOnChange=false
builder.ConfigureAppConfiguration is there to configure your (main) application.
You can use builder.ConfigureHostConfiguration (see docs) to explicitly configure files to be read for the host.
builder.ConfigureHostConfiguration((hostingContext, config) =>
{
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false);
});
The host configuration is loaded. ASP.NET Core from 3.0 is built based on Generic host (rather than the Web Host of the former versions).
You can do this without inheriting from WebApplicationFactory by using the WithWebHostBuilder and ConfigureAppConfiguration extension methods:
var webAppFactory = new WebApplicationFactory<Startup>().WithWebHostBuilder(webHostBuilder =>
{
webHostBuilder.ConfigureAppConfiguration((hostingContext, configBuilder) =>
configBuilder.Sources.Where(s => s is FileConfigurationSource).ToList()
.ForEach(s => ((FileConfigurationSource)s).ReloadOnChange = false));
});
This accomplishes the same thing as your original idea (which helped me a lot!), but more compact and without the need for a separate class definition.
I just encountered the same issue.
Setting the env variable DOTNET_hostBuilder:reloadConfigOnChange to false fixed it.
This solution works for net6 when you use the Generic Host. For other hosts, maybe try replacing DOTNET_ prefix with ASPNETCORE_
To make it simple, I set it in my code before creating the WebApplicationFactory
Environment.SetEnvironmentVariable("DOTNET_hostBuilder:reloadConfigOnChange", "false");
I am trying to add settings.json file manually to a .net core 2.1 console application. So I add these NuGet packages to the project:
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.FileExtensions
Microsoft.Extensions.Configuration.Json
and create the appsettings.json file like this:
{
"Section1": {
"Prop1": "value",
"Prop2": 300
}
}
Finally, I try to get value from the settings file like this:
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
_configuration = builder.Build();
var section = _configuration.GetSection("Section1");//section.Value is null
var test = _configuration.GetSection("Section1:Prop1");//it returns the proper value
var model = section as Section1Model;
But, section.Value is null and in consequence, the model is null. If I try to get values like _configuration.GetSection("Section1:Prop1") it returns the correct value. Also, If I call _configuration.GetSection("Section1).GetChildren() it returns a collection of settings. What I did wrong?
P.S: I promise the settings file is copied to the bin folder
ConfigurationBuilder only returns generic IConfiguration instances. If you want a strongly typed model out of that, it has to be bound first. There are several ways of doing that -- Microsoft's own implementation lives in Microsoft.Extensions.Configuration.Binder. This then gives you access to the static class ConfigurationBinder in several ways with extension methods on IConfiguration:
var model = _configuration.GetSection("Section1").Get<Section1Model>();
Oddly enough there's no extension method for directly getting a section into an object, but it would be easy enough to write one.
If you're using dependency injection (Microsoft.Extensions.DependencyInjection, Microsoft.Extensions.Options.ConfigurationExtensions) there'll be a .Configure<Section1Model>() extension method to register this binding.
I have a .NET Core 2.0 project using a JSON configuration file, via the Microsoft.Extensions.Configuration.Json provider.
This application is a utility application to support another application that I do not control.
To keep consistency with that other application's configuration file format/style, multi-word setting keys use dashes between words.
Example JSON:
{
"multi-word-setting": "setting value"
}
Example settings class:
public class AppSettings
{
// Pascal casing, as is typical in C#
public string MultiWordSetting { get; set; }
}
Example application code:
class Program
{
private static void Main ( string[ ] args )
{
IConfigurationBuilder configBuilder = new ConfigurationBuilder( ).SetBasePath( Environment.CurrentDirectory ).AddJsonFile( "my-settings.json", true, true );
IConfigurationRoot configRoot = configBuilder.Build( );
AppSettings config = new AppSettings( );
configRoot.Bind( config );
Console.WriteLine( config.MultiWordSetting );
}
}
However, given that hyphens are illegal in identifiers in C#, how can I follow typical C# naming conventions while also following the defined style of the application I am supporting?
I know I can use Newtonsoft and its JsonPropertyAttribute to just manually deal with the json data, but I'd prefer to make this work without "external" libraries, if possible. Besides, JSON.Net is over 20x larger, and the configuration libraries handle other stuff, such as automatic reloading, binding, merging, and optional files.
I've tried adding DataMember attributes to the properties of my class, to indicate the name of the json property, but that doesn't do the trick.
Is there a way to do this, with the .NET Core Microsoft.Extensions.Configuration.Json provider?
While I was writing the question, I decided to dive into the .net core source and found that no, it is not possible to do what I wanted to do.
So, I decided to fix it and, pending the outcome of ASP.Net Configuration Pull Request 775, it may be possible in a future version of .net core. Please feel free to review/scrutinize that pull request.
Until then, a relatively simple workaround is to bind the configuration as normal and then manually access any unsupported settings via the ConfigurationRoot object's indexer.
Note that, if you're using the automatic reload feature, you'd have to manually handle setting the property on reload, too.
I am facing issue with visual studio 2015 express addition.I have a console application and I wanted to keep some value in configuration file but with VS2015 there is no option available to add a App.config file instead of that it's giving me to add config.json file.
Now I don't have any idea how to keep and retrieve value inside the json.config.
With the previous version of VS2015, it was very simple all I need to do was to create the object of Configuration manager and call respective method.
I don't know why they removed this features from VS2015.
Please give me resolution on this.
With ASP.NET 5 configuration is moved to json files.
You can find some info here:
http://www.mikesdotnetting.com/article/284/asp-net-5-configuration
http://whereslou.com/2014/05/23/asp-net-vnext-moving-parts-iconfiguration/
Below constructor:
Below example will read value "somevalue" for property "OuterKey:InnerKey" from config.json file.
Constructor for Program:
public void Program()
{
var configurationBuilder = new ConfigurationBuilder()
.AddJsonFile("config.json")
.AddEnvironmentVariables();
var myConfiguration = configurationBuilder.Build();
string value = myConfiguration["OuterKey:InnerKey"];
}
Config.json:
"OuterKey": {
"InnerKey": "somevalue"
}
I want to create an ext.js store that can be shared across c# projects. I defined my store in the Services project under Scripts/Store/Hierarchies.js. The store is named NCS.store.Hierarchies.
Ext.define('NCS.store.Hierarchies', {
requires: [
'Ext.data.proxy.Proxy',
'Ext.data.Operation',
'Ext.data.reader.Json',
'NCS.store.SelectedHierarchies'
],
In a different c# project I now want to reference this store-
Ext.widget({
id: 'hierarchyPanel',
xtype: 'panel',
border: true,
frame: true,
title: 'Hierarchy Selector',
layout: {
type: 'hbox',
pack: 'start',
align: 'stretch'
},
collapsible: true,
items: NCS.store.Hierarchies.getComboArray().concat(
Ext.create('Ext.Button', {
id: 'hierarchyClear',
text: 'Clear'
})),
renderTo: this.constants.hierarchiesId,
listeners: {
show: {
fn: function (t, o) {
t.doLayout();
}
}
}
});
How do I properly reference this store? Currently I'm getting a not found error (it's looking in the current c# project url instead of the one that actually contains the store).
> GET
> http://localhost/Orchard/NCS.Reporting.PODS/NCS/store/Hierarchies.js?_dc=1405085182757
> 404 (Not Found)
I think it should be looking
http://localhost/Orchard/NCS.Services.PODS/NCS/store/Hierarchies.js?_dc=1405085182757
Also since it's looking under NCS/store I'm wondering if I need to change the folder layout to match my naming convention.
I would consider mapping the folder where the scripts are stored as a virtual directory in IIS so that the web server can serve them in response to web requests.
You can use the ExtJs Loader object -
// load up all of our dependencies
Ext.Loader.setConfig({
enabled: true,
paths: {
'NCS': Config.RootUrl + 'Modules/NCS.Services.PODS/Scripts'
}
});
I need to specify where to find NCS for ExtJS to locate the correct file. Now that I have the NCS path loaded I can use the code above to reference NCS.store.Hierarchies.