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.

-example local - -

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 +}