diff --git a/DotNest.Core.SDK.sln b/DotNest.Core.SDK.sln
index a478a59..2c3a53a 100644
--- a/DotNest.Core.SDK.sln
+++ b/DotNest.Core.SDK.sln
@@ -27,6 +27,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
.github\workflows\validate-pull-request.yml = .github\workflows\validate-pull-request.yml
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{7BE78863-16CE-4AA3-8C46-7761183142DB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNest.Core.SDK.Tests.UI", "test\DotNest.Core.SDK.Tests.UI\DotNest.Core.SDK.Tests.UI.csproj", "{13764086-2125-4C44-AFC2-665AC3C89AC0}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -41,6 +45,10 @@ Global
{2A65FF2E-0C9C-4FEF-9136-B575141355AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A65FF2E-0C9C-4FEF-9136-B575141355AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A65FF2E-0C9C-4FEF-9136-B575141355AE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {13764086-2125-4C44-AFC2-665AC3C89AC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {13764086-2125-4C44-AFC2-665AC3C89AC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {13764086-2125-4C44-AFC2-665AC3C89AC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {13764086-2125-4C44-AFC2-665AC3C89AC0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -50,6 +58,7 @@ Global
{4415DF94-4550-45C4-85DA-2741284D2C01} = {C0E663BB-B9D0-49AA-BBEB-ECA748632007}
{2A65FF2E-0C9C-4FEF-9136-B575141355AE} = {4415DF94-4550-45C4-85DA-2741284D2C01}
{190B979E-A5AB-42A4-85CE-8A94044706DF} = {7E3915D4-E24A-45FD-887C-3CB4F445C30B}
+ {13764086-2125-4C44-AFC2-665AC3C89AC0} = {7BE78863-16CE-4AA3-8C46-7761183142DB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3E281D9A-C9FF-49D6-A7E7-192EB8DC0074}
diff --git a/src/DotNest.Core.SDK.Web/DotNest.Core.SDK.Web.csproj b/src/DotNest.Core.SDK.Web/DotNest.Core.SDK.Web.csproj
index 8badade..b0e04ec 100644
--- a/src/DotNest.Core.SDK.Web/DotNest.Core.SDK.Web.csproj
+++ b/src/DotNest.Core.SDK.Web/DotNest.Core.SDK.Web.csproj
@@ -35,6 +35,7 @@
+
diff --git a/src/DotNest.Core.SDK.Web/Program.cs b/src/DotNest.Core.SDK.Web/Program.cs
index a424958..4185ba9 100644
--- a/src/DotNest.Core.SDK.Web/Program.cs
+++ b/src/DotNest.Core.SDK.Web/Program.cs
@@ -1,5 +1,6 @@
using Lombiq.Hosting.Tenants.Management.Extensions;
using OrchardCore.Logging;
+using System.Diagnostics.CodeAnalysis;
var builder = WebApplication.CreateBuilder(args);
@@ -29,3 +30,15 @@
app.UseStaticFiles();
app.UseOrchardCore();
app.Run();
+
+[SuppressMessage(
+ "Design",
+ "CA1050: Declare types in namespaces",
+ Justification = "As described here: https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests.")]
+public partial class Program
+{
+ protected Program()
+ {
+ // Nothing to do here.
+ }
+}
diff --git a/src/Themes/Sample.Theme/Manifest.cs b/src/Themes/Sample.Theme/Manifest.cs
index 20ce48b..0930342 100644
--- a/src/Themes/Sample.Theme/Manifest.cs
+++ b/src/Themes/Sample.Theme/Manifest.cs
@@ -7,7 +7,7 @@
Version = "0.0.1",
Website = "https://github.com/Lombiq/DotNest-Core-SDK",
Description = "A sample DotNest theme for local development. It must be packaged and used as a Media Theme on DotNest.",
- BaseTheme = "Lombiq.BaseTheme",
+ BaseTheme = "TheTheme",
Dependencies = new[]
{
FeatureNames.MediaThemeBridge
diff --git a/src/Themes/Sample.Theme/Recipes/DotNest.Core.SDK.MediaTheme.recipe.json b/src/Themes/Sample.Theme/Recipes/DotNest.Core.SDK.MediaTheme.recipe.json
index 9684a83..e4a99b6 100644
--- a/src/Themes/Sample.Theme/Recipes/DotNest.Core.SDK.MediaTheme.recipe.json
+++ b/src/Themes/Sample.Theme/Recipes/DotNest.Core.SDK.MediaTheme.recipe.json
@@ -2,8 +2,8 @@
"name": "DotNest.Core.SDK.MediaTheme",
"displayName": "Media Theme",
"description": "A recipe created with the media-theme-deployment tool.",
- "author": "",
- "website": "",
+ "author": "Lombiq Technologies",
+ "website": "https://github.com/Lombiq/DotNest-Core-SDK",
"version": "",
"issetuprecipe": false,
"categories": [],
@@ -47,4 +47,4 @@
]
}
]
-}
\ No newline at end of file
+}
diff --git a/src/Themes/Sample.Theme/Recipes/DotNest.Core.SDK.Setup.recipe.json b/src/Themes/Sample.Theme/Recipes/DotNest.Core.SDK.Setup.recipe.json
index f7abfa9..bee51ae 100644
--- a/src/Themes/Sample.Theme/Recipes/DotNest.Core.SDK.Setup.recipe.json
+++ b/src/Themes/Sample.Theme/Recipes/DotNest.Core.SDK.Setup.recipe.json
@@ -2,13 +2,16 @@
"name": "DotNest.Core.SDK.Setup",
"displayName": "DotNest Core SDK - Setup",
"description": "Settings and features required only for development.",
- "author": "DotNestCoreSDK",
- "website": "https://www.dotnestcoresdk.com",
+ "author": "Lombiq Technologies",
+ "website": "https://github.com/Lombiq/DotNest-Core-SDK",
"version": "1.0",
"issetuprecipe": true,
"categories": [ "dotnestcoresdk" ],
"tags": [],
-
+ "variables": {
+ "homeContentItemId": "[js:uuid()]",
+ "now": "[js: new Date().toISOString()]"
+ },
"steps": [
{
"name": "feature",
@@ -121,13 +124,10 @@
"Lombiq.Hosting.Tenants.Admin.Login.SubTenant",
"Lombiq.Hosting.Tenants.Management.ForbiddenTenantNames",
"Lombiq.Hosting.MediaTheme",
- "Lombiq.Privacy",
- "Lombiq.Privacy.ConsentBanner",
- "Lombiq.Privacy.FormConsent",
- "Lombiq.Privacy.RegistrationConsent",
// Themes
"TheAdmin",
+ "TheTheme",
"Lombiq.BaseTheme",
"Sample.Theme"
]
@@ -135,25 +135,68 @@
{
"name": "themes",
"admin": "TheAdmin",
- "site": "Sample.Theme"
+ "site": "TheTheme"
+ },
+ {
+ "name": "Content",
+ "data": [
+ {
+ "ContentItemId": "[js: variables('homeContentItemId')]",
+ "ContentItemVersionId": "[js: uuid()]",
+ "ContentType": "Page",
+ "DisplayText": "This is DotNest Core SDK",
+ "Latest": true,
+ "Published": true,
+ "ModifiedUtc": "[js: variables('now')]",
+ "PublishedUtc": "[js: variables('now')]",
+ "CreatedUtc": "[js: variables('now')]",
+ "Owner": "[js: parameters('AdminUserId')]",
+ "Author": "[js: parameters('AdminUsername')]",
+ "TitlePart": {
+ "Title": "This is DotNest Core SDK"
+ },
+ "AutoroutePart": {
+ "Path": "this-is-dotnest-core-sdk",
+ "SetHomepage": true,
+ "Disabled": false,
+ "RouteContainedItems": false,
+ "Absolute": false
+ },
+ "FlowPart": {
+ "Widgets": []
+ }
+ }
+ ]
+ },
+ {
+ "name": "Settings",
+ "HomeRoute": {
+ "Area": "OrchardCore.Contents",
+ "Controller": "Item",
+ "Action": "Display",
+ "contentItemId": "[js: variables('homeContentItemId')]"
+ }
+ },
+ {
+ "name": "Roles",
+ "Roles": [
+ {
+ "Name": "Anonymous",
+ "Description": "Anonymous role",
+ "Permissions": [
+ "ViewContent"
+ ]
+ }
+ ]
},
{
"name": "recipes",
"Values": [
- {
- "executionid": "DotNest.Core.SDK.Web",
- "name": "Lombiq.BaseTheme.LayersAndZones"
- },
{
"executionid": "DotNest.Core.SDK.Web",
"name": "DotNest.Core.SDK.MediaTheme"
}
]
- },
- {
- "name": "mediatheme",
- "ClearMediaThemeFolder": false,
- "BaseThemeId": "Lombiq.BaseTheme"
}
]
}
diff --git a/src/Themes/Sample.Theme/Recipes/_MediaTheme/Templates/Widget__LayoutInjection.liquid b/src/Themes/Sample.Theme/Recipes/_MediaTheme/Templates/Widget__LayoutInjection.liquid
index 4a07df7..6098114 100644
--- a/src/Themes/Sample.Theme/Recipes/_MediaTheme/Templates/Widget__LayoutInjection.liquid
+++ b/src/Themes/Sample.Theme/Recipes/_MediaTheme/Templates/Widget__LayoutInjection.liquid
@@ -1,4 +1,4 @@
-{% zone "Header" %}
+{% zone "Messages" %}
This is a template rendered from your custom theme. Once deployed to the Media Theme, it'll be hosted from there.
Below is an image also stored in the theme's wwwroot folder. Note that the URL of the image starts with /mediatheme
.
diff --git a/src/Themes/Sample.Theme/Sample.Theme.csproj b/src/Themes/Sample.Theme/Sample.Theme.csproj
index dd13d76..9039331 100644
--- a/src/Themes/Sample.Theme/Sample.Theme.csproj
+++ b/src/Themes/Sample.Theme/Sample.Theme.csproj
@@ -15,7 +15,6 @@
-
@@ -26,7 +25,7 @@
- Lombiq.BaseTheme
+ TheTheme
diff --git a/src/Themes/Sample.Theme/Views/Widget-LayoutInjection.liquid b/src/Themes/Sample.Theme/Views/Widget-LayoutInjection.liquid
deleted file mode 100644
index 4a07df7..0000000
--- a/src/Themes/Sample.Theme/Views/Widget-LayoutInjection.liquid
+++ /dev/null
@@ -1,12 +0,0 @@
-{% zone "Header" %}
-
-
This is a template rendered from your custom theme. Once deployed to the Media Theme, it'll be hosted from there.
-Below is an image also stored in the theme's wwwroot folder. Note that the URL of the image starts with /mediatheme
.
- Once it's deployed to the Media Theme, the URL can stay the same, but it'll be served from the Media Library.
-
-
-Now let's render a shape that's actually coming from the Media Theme.
-
-{{ "Example" | shape_new | shape_render }}
-
-{% endzone %}
diff --git a/src/Themes/Sample.Theme/Views/Widget__LayoutInjection.liquid b/src/Themes/Sample.Theme/Views/Widget__LayoutInjection.liquid
index 4a07df7..6098114 100644
--- a/src/Themes/Sample.Theme/Views/Widget__LayoutInjection.liquid
+++ b/src/Themes/Sample.Theme/Views/Widget__LayoutInjection.liquid
@@ -1,4 +1,4 @@
-{% zone "Header" %}
+{% zone "Messages" %}
This is a template rendered from your custom theme. Once deployed to the Media Theme, it'll be hosted from there.
Below is an image also stored in the theme's wwwroot folder. Note that the URL of the image starts with /mediatheme
.
diff --git a/test/DotNest.Core.SDK.Tests.UI/Constants/Recipes.cs b/test/DotNest.Core.SDK.Tests.UI/Constants/Recipes.cs
new file mode 100644
index 0000000..58b801b
--- /dev/null
+++ b/test/DotNest.Core.SDK.Tests.UI/Constants/Recipes.cs
@@ -0,0 +1,6 @@
+namespace DotNest.Core.SDK.Tests.UI.Constants;
+
+public static class Recipes
+{
+ public const string DefaultRecipeId = "DotNest.Core.SDK.Tests.Default";
+}
diff --git a/test/DotNest.Core.SDK.Tests.UI/DotNest.Core.SDK.Tests.UI.csproj b/test/DotNest.Core.SDK.Tests.UI/DotNest.Core.SDK.Tests.UI.csproj
new file mode 100644
index 0000000..bb049a7
--- /dev/null
+++ b/test/DotNest.Core.SDK.Tests.UI/DotNest.Core.SDK.Tests.UI.csproj
@@ -0,0 +1,25 @@
+
+
+
+ net6.0
+ false
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
diff --git a/test/DotNest.Core.SDK.Tests.UI/Helpers/SetupHelpers.cs b/test/DotNest.Core.SDK.Tests.UI/Helpers/SetupHelpers.cs
new file mode 100644
index 0000000..7a807d2
--- /dev/null
+++ b/test/DotNest.Core.SDK.Tests.UI/Helpers/SetupHelpers.cs
@@ -0,0 +1,28 @@
+using DotNest.Core.SDK.Tests.UI.Constants;
+using Lombiq.Tests.UI.Extensions;
+using Lombiq.Tests.UI.Pages;
+using Lombiq.Tests.UI.Services;
+using OpenQA.Selenium;
+using Shouldly;
+using System;
+using System.Threading.Tasks;
+
+namespace DotNest.Core.SDK.Tests.UI.Helpers;
+
+public static class SetupHelpers
+{
+ public static async Task RunSetupAsync(UITestContext context)
+ {
+ var homepageUri = await context.GoToSetupPageAndSetupOrchardCoreAsync(
+ new OrchardCoreSetupParameters(context)
+ {
+ SiteName = "DotNest Core SDK",
+ RecipeId = Recipes.DefaultRecipeId,
+ SiteTimeZoneValue = "Europe/Budapest",
+ });
+
+ context.Get(By.ClassName("navbar-brand")).Text.ShouldBe("DotNest Core SDK");
+
+ return homepageUri;
+ }
+}
diff --git a/test/DotNest.Core.SDK.Tests.UI/Readme.md b/test/DotNest.Core.SDK.Tests.UI/Readme.md
new file mode 100644
index 0000000..6adbcfc
--- /dev/null
+++ b/test/DotNest.Core.SDK.Tests.UI/Readme.md
@@ -0,0 +1,5 @@
+# DotNest Core SDK UI Tests
+
+## Overview
+
+This project contains a sample UI test for the DotNest Core SDK, which ensures that basic functionality is working. You can use it as a starting point for your own UI tests. The project uses the [Lombiq UI Testing Toolbox for Orchard Core project](https://github.com/Lombiq/UI-Testing-Toolbox) which gives you a framework for writing UI tests. For more info please check out its documentation. For more UI test examples see the [`Lombiq.Tests.UI.Samples` repository](https://github.com/Lombiq/UI-Testing-Toolbox/blob/dev/Lombiq.Tests.UI.Samples/Readme.md).
diff --git a/test/DotNest.Core.SDK.Tests.UI/Recipes/DotNest.Core.SDK.Tests.Configuration.Tests.recipe.json b/test/DotNest.Core.SDK.Tests.UI/Recipes/DotNest.Core.SDK.Tests.Configuration.Tests.recipe.json
new file mode 100644
index 0000000..5a04300
--- /dev/null
+++ b/test/DotNest.Core.SDK.Tests.UI/Recipes/DotNest.Core.SDK.Tests.Configuration.Tests.recipe.json
@@ -0,0 +1,35 @@
+{
+ "name": "DotNest.Core.SDK.Tests.Configuration.Tests",
+ "displayName": "TEST: DotNest Core SDK - Configuration Tests",
+ "description": "Common configuration necessary for UI tests.",
+ "author": "Lombiq Technologies",
+ "website": "https://github.com/Lombiq/DotNest-Core-SDK",
+ "version": "1.0",
+ "issetuprecipe": false,
+ "categories": [ "test" ],
+ "tags": [ "test", "HideFromSetupScreen" ],
+
+ "steps": [
+ {
+ "name": "feature",
+ "enable": [
+ "OrchardCore.Localization"
+ ]
+ },
+ {
+ "name": "settings",
+ // To make sure that e.g. numbers and dates are formatted the same way on all machines we have to specify the
+ // culture too.
+ "UseCdn": false,
+ "SmtpSettings": {
+ "DefaultSender": "sender@example.com"
+ },
+ "LocalizationSettings": {
+ "DefaultCulture": "en-US",
+ "SupportedCultures": [
+ "en-US"
+ ]
+ }
+ }
+ ]
+}
diff --git a/test/DotNest.Core.SDK.Tests.UI/Recipes/DotNest.Core.SDK.Tests.Default.recipe.json b/test/DotNest.Core.SDK.Tests.UI/Recipes/DotNest.Core.SDK.Tests.Default.recipe.json
new file mode 100644
index 0000000..4c06737
--- /dev/null
+++ b/test/DotNest.Core.SDK.Tests.UI/Recipes/DotNest.Core.SDK.Tests.Default.recipe.json
@@ -0,0 +1,27 @@
+{
+ "name": "DotNest.Core.SDK.Tests.Default",
+ "displayName": "TEST: DotNest Core SDK - Default tenant",
+ "description": "Setup recipe for the default tenant of DotNest Tenants SDK, for automated UI test execution.",
+ "author": "Lombiq Technologies",
+ "website": "https://github.com/Lombiq/DotNest-Core-SDK",
+ "version": "1.0",
+ "issetuprecipe": true,
+ "categories": [ "developer" ],
+ "tags": [ "dotnest", "test", "HideFromSetupScreen" ],
+
+ "steps": [
+ {
+ "name": "recipes",
+ "Values": [
+ {
+ "executionid": "DotNest.Core.SDK.Tests.UI",
+ "name": "DotNest.Core.SDK.Setup"
+ },
+ {
+ "executionid": "DotNest.Core.SDK.Tests.UI",
+ "name": "DotNest.Core.SDK.Tests.Configuration.Tests"
+ }
+ ]
+ }
+ ]
+}
diff --git a/test/DotNest.Core.SDK.Tests.UI/Tests/BasicOrchardFeaturesTests.cs b/test/DotNest.Core.SDK.Tests.UI/Tests/BasicOrchardFeaturesTests.cs
new file mode 100644
index 0000000..68293e3
--- /dev/null
+++ b/test/DotNest.Core.SDK.Tests.UI/Tests/BasicOrchardFeaturesTests.cs
@@ -0,0 +1,20 @@
+using DotNest.Core.SDK.Tests.UI.Constants;
+using Lombiq.Tests.UI.Extensions;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace DotNest.Core.SDK.Tests.UI.Tests;
+
+public class BasicOrchardFeaturesTests : UITestBase
+{
+ public BasicOrchardFeaturesTests(ITestOutputHelper testOutputHelper)
+ : base(testOutputHelper)
+ {
+ }
+
+ [Fact]
+ public Task BasicOrchardFeaturesShouldWork() =>
+ ExecuteTestAsync(
+ context => context.TestBasicOrchardFeaturesExceptRegistrationAsync(Recipes.DefaultRecipeId));
+}
diff --git a/test/DotNest.Core.SDK.Tests.UI/UITestBase.cs b/test/DotNest.Core.SDK.Tests.UI/UITestBase.cs
new file mode 100644
index 0000000..4f0fadb
--- /dev/null
+++ b/test/DotNest.Core.SDK.Tests.UI/UITestBase.cs
@@ -0,0 +1,22 @@
+using DotNest.Core.SDK.Tests.UI.Helpers;
+using Lombiq.Tests.UI;
+using Lombiq.Tests.UI.Services;
+using System;
+using System.Threading.Tasks;
+using Xunit.Abstractions;
+
+namespace DotNest.Core.SDK.Tests.UI;
+
+public class UITestBase : OrchardCoreUITestBase
+{
+ protected UITestBase(ITestOutputHelper testOutputHelper)
+ : base(testOutputHelper)
+ {
+ }
+
+ protected override Task ExecuteTestAfterSetupAsync(
+ Func testAsync,
+ Browser browser,
+ Func changeConfigurationAsync) =>
+ ExecuteTestAsync(testAsync, browser, SetupHelpers.RunSetupAsync, changeConfigurationAsync);
+}
diff --git a/test/DotNest.Core.SDK.Tests.UI/xunit.runner.json b/test/DotNest.Core.SDK.Tests.UI/xunit.runner.json
new file mode 100644
index 0000000..db580a4
--- /dev/null
+++ b/test/DotNest.Core.SDK.Tests.UI/xunit.runner.json
@@ -0,0 +1,6 @@
+{
+ "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
+ "parallelizeAssembly": false,
+ "parallelizeTestCollections": true,
+ "stopOnFail": true
+}