From b40496268d779575195c7c702fcf39bd6c441f2a Mon Sep 17 00:00:00 2001 From: akfakmot Date: Thu, 26 Sep 2024 15:08:33 +0200 Subject: [PATCH 1/2] Add automatic tests of results of Kentico.Xperience.UMT.Example.Console Add: Add automatic tests of results of Kentico.Xperience.UMT.Example.Console --- Directory.Packages.props | 8 +- Kentico.Xperience.UMT.sln | 28 ++- README.md | 7 + test.runsettings | 11 ++ .../Enums/EventLogSeverity.cs | 15 ++ .../Extensions/IEnumerableExtensions.cs | 24 +++ .../Extensions/PageTreeItemExtensions.cs | 14 ++ .../Extensions/PlaywrightExtensions.cs | 14 ++ .../Helpers/PageTreeItem.cs | 21 ++ .../Kentico.Xperience.UMT.Tests.csproj | 41 ++++ .../Resources/kentico_brand.png | Bin 0 -> 2636 bytes .../Tests/01_EventlogTests.cs | 8 + .../Tests/02_ChannelTests.cs | 179 ++++++++++++++++++ .../Tests/03_ContentHubTests.cs | 93 +++++++++ .../Tests/04_MediaLibraryTests.cs | 78 ++++++++ .../Tests/05_ChannelManagementTests.cs | 72 +++++++ .../Tests/06_LanguageTests.cs | 37 ++++ .../Tests/07_UserTests.cs | 30 +++ .../Tests/08_ContentTypeTests.cs | 37 ++++ .../Tests/09_TaxonomyTests.cs | 46 +++++ .../Tests/AdminTestBase.cs | 179 ++++++++++++++++++ .../packages.lock.json | 145 ++++++++++++++ 22 files changed, 1081 insertions(+), 6 deletions(-) create mode 100644 test.runsettings create mode 100644 tests/Kentico.Xperience.UMT.Tests/Enums/EventLogSeverity.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Extensions/IEnumerableExtensions.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Extensions/PageTreeItemExtensions.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Extensions/PlaywrightExtensions.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Helpers/PageTreeItem.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Kentico.Xperience.UMT.Tests.csproj create mode 100644 tests/Kentico.Xperience.UMT.Tests/Resources/kentico_brand.png create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/01_EventlogTests.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/02_ChannelTests.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/03_ContentHubTests.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/04_MediaLibraryTests.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/05_ChannelManagementTests.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/06_LanguageTests.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/07_UserTests.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/08_ContentTypeTests.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/09_TaxonomyTests.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/AdminTestBase.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/packages.lock.json diff --git a/Directory.Packages.props b/Directory.Packages.props index 56eaa69..53a3c6c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,12 +6,18 @@ true + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -25,7 +31,7 @@ - + diff --git a/Kentico.Xperience.UMT.sln b/Kentico.Xperience.UMT.sln index 19f54e4..70abfb5 100644 --- a/Kentico.Xperience.UMT.sln +++ b/Kentico.Xperience.UMT.sln @@ -1,18 +1,25 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kentico.Xperience.UMT", "src\Kentico.Xperience.UMT\Kentico.Xperience.UMT.csproj", "{F499DE79-C15E-4ABA-9E42-E0A243E0F598}" +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kentico.Xperience.UMT", "src\Kentico.Xperience.UMT\Kentico.Xperience.UMT.csproj", "{F499DE79-C15E-4ABA-9E42-E0A243E0F598}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kentico.Xperience.UMT.Example.Console", "examples\Kentico.Xperience.UMT.Example.Console\Kentico.Xperience.UMT.Example.Console.csproj", "{B34D5B62-F958-48E4-84A3-35343529FCF7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kentico.Xperience.UMT.Example.Console", "examples\Kentico.Xperience.UMT.Example.Console\Kentico.Xperience.UMT.Example.Console.csproj", "{B34D5B62-F958-48E4-84A3-35343529FCF7}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{A22B7345-BFCB-4BB2-85DA-A32BE7024061}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kentico.Xperience.UMT.Example.AdminApp", "examples\Kentico.Xperience.UMT.Example.AdminApp\Kentico.Xperience.UMT.Example.AdminApp.csproj", "{4ABF76B5-3ED7-44CF-9FFA-39F299BD947C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kentico.Xperience.UMT.Example.AdminApp", "examples\Kentico.Xperience.UMT.Example.AdminApp\Kentico.Xperience.UMT.Example.AdminApp.csproj", "{4ABF76B5-3ED7-44CF-9FFA-39F299BD947C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kentico.Xperience.UMT.Examples", "examples\Kentico.Xperience.UMT.Examples\Kentico.Xperience.UMT.Examples.csproj", "{85138B06-9F3F-40A6-8465-479F591D2845}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kentico.Xperience.UMT.Examples", "examples\Kentico.Xperience.UMT.Examples\Kentico.Xperience.UMT.Examples.csproj", "{85138B06-9F3F-40A6-8465-479F591D2845}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utils", "Utils", "{66C1E923-BA9C-4674-8534-F456FE27592A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kentico.Xperience.UMT.DocUtils", "utils\Kentico.Xperience.UMT.DocUtils\Kentico.Xperience.UMT.DocUtils.csproj", "{71299533-CB05-4068-B5C3-9BCE76413E26}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kentico.Xperience.UMT.DocUtils", "utils\Kentico.Xperience.UMT.DocUtils\Kentico.Xperience.UMT.DocUtils.csproj", "{71299533-CB05-4068-B5C3-9BCE76413E26}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{41F4E25E-E6DF-4D03-85C9-7428A317F207}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kentico.Xperience.UMT.Tests", "tests\Kentico.Xperience.UMT.Tests\Kentico.Xperience.UMT.Tests.csproj", "{2601A1AE-938B-4C67-A859-655B14DAE69A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -40,11 +47,22 @@ Global {71299533-CB05-4068-B5C3-9BCE76413E26}.Debug|Any CPU.Build.0 = Debug|Any CPU {71299533-CB05-4068-B5C3-9BCE76413E26}.Release|Any CPU.ActiveCfg = Release|Any CPU {71299533-CB05-4068-B5C3-9BCE76413E26}.Release|Any CPU.Build.0 = Release|Any CPU + {2601A1AE-938B-4C67-A859-655B14DAE69A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2601A1AE-938B-4C67-A859-655B14DAE69A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2601A1AE-938B-4C67-A859-655B14DAE69A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2601A1AE-938B-4C67-A859-655B14DAE69A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {B34D5B62-F958-48E4-84A3-35343529FCF7} = {A22B7345-BFCB-4BB2-85DA-A32BE7024061} {4ABF76B5-3ED7-44CF-9FFA-39F299BD947C} = {A22B7345-BFCB-4BB2-85DA-A32BE7024061} {85138B06-9F3F-40A6-8465-479F591D2845} = {A22B7345-BFCB-4BB2-85DA-A32BE7024061} {71299533-CB05-4068-B5C3-9BCE76413E26} = {66C1E923-BA9C-4674-8534-F456FE27592A} + {2601A1AE-938B-4C67-A859-655B14DAE69A} = {41F4E25E-E6DF-4D03-85C9-7428A317F207} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C0A71F59-A92C-4A54-A8AF-735C1DB21149} EndGlobalSection EndGlobal diff --git a/README.md b/README.md index f89083c..47a4523 100644 --- a/README.md +++ b/README.md @@ -78,3 +78,10 @@ See [`SUPPORT.md`](https://github.com/Kentico/.github/blob/main/SUPPORT.md#full- ## Security For any security issues see [Kentico's `SECURITY.md`](https://github.com/Kentico/.github/blob/main/SECURITY.md). + +## Testing + +1. Migrate to blank template Kentico XbK project by Kentico.Xperience.UMT.Example.Console +2. Configure $SolutionDir\test.runsettings per the project's settings +3. Ensure test.runsettings file is used in Visual Studio: Top menu -> Test -> Configure Run Settings -> Select Solution Wide runsettings File +4. Run tests from Test explorer diff --git a/test.runsettings b/test.runsettings new file mode 100644 index 0000000..26ed67d --- /dev/null +++ b/test.runsettings @@ -0,0 +1,11 @@ + + + + + + http://localhost:53798 + administrator + administrator + + + \ No newline at end of file diff --git a/tests/Kentico.Xperience.UMT.Tests/Enums/EventLogSeverity.cs b/tests/Kentico.Xperience.UMT.Tests/Enums/EventLogSeverity.cs new file mode 100644 index 0000000..3d59624 --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Enums/EventLogSeverity.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TestAfterMigration.Enums +{ + public enum EventLogSeverity + { + Info, + Warning, + Error + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Extensions/IEnumerableExtensions.cs b/tests/Kentico.Xperience.UMT.Tests/Extensions/IEnumerableExtensions.cs new file mode 100644 index 0000000..6a101f8 --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Extensions/IEnumerableExtensions.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TestAfterMigration.Extensions +{ + public static class IEnumerableExtensions + { + public static IEnumerable SelectManyRecursive(this IEnumerable source, Func> selector) + { + if (source == null) throw new ArgumentNullException("source"); + if (selector == null) throw new ArgumentNullException("selector"); + + return !source.Any() ? source : + source.Concat( + source + .SelectMany(i => selector(i)) + .SelectManyRecursive(selector) + ); + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Extensions/PageTreeItemExtensions.cs b/tests/Kentico.Xperience.UMT.Tests/Extensions/PageTreeItemExtensions.cs new file mode 100644 index 0000000..765f170 --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Extensions/PageTreeItemExtensions.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TestAfterMigration.Helpers; + +namespace TestAfterMigration.Extensions +{ + public static class PageTreeItemExtensions + { + public static IEnumerable Family(this PageTreeItem item) => [item, ..item.Children.SelectManyRecursive(x => x.Children)]; + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Extensions/PlaywrightExtensions.cs b/tests/Kentico.Xperience.UMT.Tests/Extensions/PlaywrightExtensions.cs new file mode 100644 index 0000000..41c7d41 --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Extensions/PlaywrightExtensions.cs @@ -0,0 +1,14 @@ +using Microsoft.Playwright; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TestAfterMigration.Extensions +{ + public static class PlaywrightExtensions + { + public static Task WaitForVisible(this ILocator locator) => locator.Nth(0).WaitForAsync(new LocatorWaitForOptions { State = WaitForSelectorState.Visible }); + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Helpers/PageTreeItem.cs b/tests/Kentico.Xperience.UMT.Tests/Helpers/PageTreeItem.cs new file mode 100644 index 0000000..305a778 --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Helpers/PageTreeItem.cs @@ -0,0 +1,21 @@ +using Microsoft.Playwright; +using TestAfterMigration.Extensions; + +namespace TestAfterMigration.Helpers +{ + public class PageTreeItem(IPage page, string nodeID) + { + public async Task LoadInfo() => Title = (await TitleElement.TextContentAsync())!; + + public string? Title { get; private set; } = null; + public ILocator Locator => page.Locator($"[data-testid-nodeid=\"{nodeID}\"]"); + public IEnumerable Children { get; set; } = []; + public ILocator TitleElement => Locator.GetByTestId("tree-item-title").Nth(0); + public Task ClickAsync() => TitleElement.ClickAsync(); + public async Task WaitBreadcrumbsLoaded() + { + string pageTitle = (await Locator.GetByTestId("tree-item-title").Nth(0).TextContentAsync())!; + await Locator.Page.GetByTestId("breadcrumbs").GetByText(pageTitle).WaitForVisible(); + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Kentico.Xperience.UMT.Tests.csproj b/tests/Kentico.Xperience.UMT.Tests/Kentico.Xperience.UMT.Tests.csproj new file mode 100644 index 0000000..0bf82b1 --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Kentico.Xperience.UMT.Tests.csproj @@ -0,0 +1,41 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + Always + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/tests/Kentico.Xperience.UMT.Tests/Resources/kentico_brand.png b/tests/Kentico.Xperience.UMT.Tests/Resources/kentico_brand.png new file mode 100644 index 0000000000000000000000000000000000000000..0ba82a643f7c30ebadb2494ebc248c71e4508fe0 GIT binary patch literal 2636 zcmV-S3bXZzP){_^hcPXPVuh*NTKeSuyL6k+WOA6yOg+!xa5x+ehr{7;I2;a# z!{Kl^91e%W;kZA7BXzgoR#1WvBOwk$!Vtsl(}`y<55pw(kHpE~TcE*5i0a2Es`i!=pRVk4Z9kE!X9ajDFO=pU08R^ zt_7rU#OiL@wSW{RtyvTyg}v5~(r%|MQ;k!2|2T!xXURQGM->!Oyk14k@9FXiDH$HO z=(zFSSX$w)z~k@UYTNu!f}$v5DwjlAh5rQ}`Ko94gQMlXpY#SF+eoglq(Vvtm!H1W zaF`6D@udODRyrG$Q%Kn$^IQ88L$9B0?1)hKx1|)OL-db>Wm{z1LZgQamRLq1Wy8X+ zpRLZQ(GS<$0o;ov6lQJkKRs%3U5s7??S&+VU z+D@lmBU=O&dKrZ(8}$9PO;?7-bdy~)NKg2i?A?=Wq5tE-uCFGDOa>~j56ZMzJwzXD zyG=E0kzJZZR>EJTcfj(6{_n40-7l<`IJig*Jdq(LmtAHMs)uL|j&HRsriXGSIx|l% zU8o%L{d(ey)V;X9Oz#3qTwL^rJH`J~OAl&EoTO6;CovW1kxfGdYDiqt^rtUz<{y%2 zDjts;D^R`kPcyp^_Wtz0uj0WW%s4+42eN*>w`+>&<|%s^poDeCyRYfYLt(bj@_|s( zB$Fav`WJ=cPJqJ@7ej>6x8#4YzR>eXZShCP6VE;*0_*O<6EcZgozpXXY5g_%-wNx`_gh zpy%_9G1(&1tG)n@AO5T{?vEQA9*xm*w^*!q%Tk$J7TYy(nF-ly;K$)&G*B<39~nRnkhoz?vUs$zi*kmwJ5R6J9XfQ z+q8_D*NuS`*^^{0@(A~4((|$Wbz1K=QWqlDkwGIk6OBB_0)fYcZwyMLB=V&1I}==K zAP{=!CtVr6!O8>fpz&NR@F)?w5k$-VM*6x7$@^8Jh@zDwN+@mbN<4W)@WVaf6Eu=| zZi*bP5R@6ngM=~&PdtK2CPfr)NU6dHp5x;RQA9{}F_a>>#l&yYCwMnN5Sj?g-W-$` zxKO|50v~y%7yx_&k--o>vZ>sM{NYpv7b1h_iYI2Y%KMI{Tv;KKnGsL16Ukojz)Rr) z!!GpWs!>GZ>sy%Oph2qZ>p^~)23Q=`a65%~YxY7vKTHEp)!?3&dw?zt-&a{7Gnr>j zJm)4yjRr4shKR+!(;F%jx-wI#)JQ<2K61u>gw zeE+LrAF84jihNgH@d>nRhS*lLL-`hn=c%e48Y|52^^ND!pkw&Hx2ne{Q-z!20&ch- zni_ufY$#KO#Xx1{%)xDf%qG)y4_LR9lZ1hcbS=w<2j4R#aAO8lZ z+3G_!Km5gFl$j+789#l0fA62erp~benw}4XgQ;;m4Q4;*jm&1(ypXRGG|Yy5O*&>B zL6+G=%mX~o>!X-n7tc)`C}f-8_6YO(>qU@WC)tw~3Av;au#8Auh|=rgcimZ$cKD5} ztfWs3h*MmPP9_lHF<1>(FLBoRz;)%3VSo|4Acq9liRu49Sx9XcU5 zM4~K7S*xH-_z6DW2#L}>daY0pA}%}iO9O0Co=0E27^0XEQjC$6Uc%PC^egh{bA3n& zdH;Ob?{{;WI~~d$|1}R(RUUoT4%z$uytVF*=9#^<;$pkjrC(XgVg}^_`yZ)mPIbpv zqb({04l}vj#gv+1+KZ~2gW4pjYgwdm8G^K^&BYa^y!Wli7S#e5mo5|*#z?RJlou7X zNYtoCauFC%QM^N(me4aU%w$ENDkd{?5d{Rvq#-j4%>n+o&gr!r`$DTwC7x)wi)U5TTQPRg=FGh+h+Cqw} zX1%r&)%k7BBUk znE>Tn;cNS`h%B4jA}^Rz@@q(FcHTS1qmWry2MY~IB`S(mmHna>j+QT@Nq_N0Yl^R7 z=Liv1Rjw-EU1JC_E5`{TWR@sx@WdT|{}7*&gw=J`?pWb*PXGK-&jI(W@Dy&T{>^f>AkwPG1rbP-pBs9b}DHK;qXp=%OdTqNxp~QA6 z^w5fn1a6r^k9GD17v#{g_w43S7LHdBgQOS7$!74qp0=zDe>tV!F+vDq2$A~SFAj&p u;cz${4u`|xa5x+ehr{7;I2;a#L&!hUOpQY{k}jP90000 await AssertNoEventlogErrors(); + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/02_ChannelTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/02_ChannelTests.cs new file mode 100644 index 0000000..fb356a6 --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/02_ChannelTests.cs @@ -0,0 +1,179 @@ +using Microsoft.Playwright; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TestAfterMigration.Extensions; +using TestAfterMigration.Helpers; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace TestAfterMigration.Tests +{ + public class _02_ChannelTests : AdminTestBase + { + [Test] + public async Task Test00100_Email_Channel_Was_Created() + { + await OpenAdminApplication("Channel management"); + await Assertions.Expect(page.GetByTestId("table-cell-ChannelDisplayName") + .Filter(new LocatorFilterOptions { HasText = "email Channel Example" })) + .ToHaveCountAsync(1); + } + + [Test] + public async Task Test00200_Web_Channel_Was_Created() + { + await OpenAdminApplication("Channel management"); + await Assertions.Expect(page.GetByTestId("table-cell-ChannelDisplayName") + .Filter(new LocatorFilterOptions { HasText = "website Channel Example" })) + .ToHaveCountAsync(1); + } + + [Test] + public async Task Test00300_Web_Channel_Has_Page_In_Different_Publish_States() + { + await OpenAdminApplication("website Channel Example"); + await SelectTopDropdownLanguage("English (United States)"); + + string[] expectedStates = ["Draft (Initial)", "Published", "Scheduled"]; + + var pageStates = new HashSet(); + var treeItems = await GetPageTreeItems(); + foreach (var item in treeItems) + { + await item.ClickAsync(); + await item.WaitBreadcrumbsLoaded(); + var status = await page.GetByTestId("breadcrumbs-status").TextContentAsync(); + pageStates.Add(status); + } + + foreach (var state in expectedStates) + { + Assert.That(pageStates.Contains(state, StringComparer.OrdinalIgnoreCase)); + } + } + + [Test] + public async Task Test00400_Web_Channel_Has_Page_With_Child() + { + await OpenAdminApplication("website Channel Example"); + await SelectTopDropdownLanguage("English (United States)"); + + var pageStates = new HashSet(); + var treeItems = await GetPageTreeItems(); + + Assert.That(treeItems.Any(x => x.Children.Count() != 0)); + } + + [Test] + public async Task Test00400_New_Page_Create_And_Delete_Succeeds() + { + await OpenAdminApplication("website Channel Example"); + await SelectTopDropdownLanguage("English (United States)"); + + string displayName = $"NewPage{Guid.NewGuid()}"; + await page.GetByTestId("create-page-button").ClickAsync(); + await page.GetByTestId("DisplayName").FillAsync(displayName); + await page.GetByTestId("content-item-action-button-confirmfirstselection").ClickAsync(); + + await page.GetByTestId("ArticleTitle").FillAsync("New Page"); + + await page.GetByTestId("ArticleDecimalNumberSample").FillAsync("123.456"); + + await page.GetByTestId("ArticleText").FillAsync("Text on\nmultiple\nlines".Replace("\n", Environment.NewLine)); + + await page.GetByTestId("file-input-upload").SetInputFilesAsync(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "Resources", "kentico_brand.png")); + + await page.GetByTestId("button-select-web-page").ClickAsync(); + await page.GetByTestId("table-row").Nth(1).ClickAsync(); + await page.GetByTestId("confirm-action").ClickAsync(); + + await page.GetByTestId("button-select-existing-content-item").ClickAsync(); + await page.GetByTestId("table-row").Nth(0).ClickAsync(); + await page.GetByTestId("confirm-action").ClickAsync(); + + await page.GetByTestId("button-select-tag").ClickAsync(); + await page.GetByTestId("CoffeaTaxonomy.Select").GetByRole(AriaRole.Treeitem).Nth(0).ClickAsync(); + await page.GetByTestId("confirm-action").ClickAsync(); + + await page.GetByTestId("content-item-menu-split-button-publish").ClickAsync(); + await page.GetByTestId("submit-form-button").ClickAsync(); + + await Debounce(); + await page.GetByTestId("submit-form-button").ClickAsync(); + + var treeItem = (await GetPageTreeItems(rootOnly: true)).First(x => x.Title == displayName); + await ValidatePageTreePageTabs(treeItem); + await treeItem.Locator.HoverAsync(); + await treeItem.Locator.Locator("div[class*=\"trailing-cell\"]").ClickAsync(); + await page.GetByTestId("delete-action").ClickAsync(); + await page.GetByTestId("confirm-action").ClickAsync(); + + await Assertions.Expect(page.GetByText("successfully deleted").Nth(0)).ToBeVisibleAsync(); + } + + [Test] + public async Task Test00500_Web_Channel_No_Errors_When_Viewing_Tabs() + { + await OpenAdminApplication("website Channel Example"); + await SelectTopDropdownLanguage("English (United States)"); + + var pageStates = new HashSet(); + var treeItems = await GetPageTreeItems(); + foreach (var item in treeItems.SelectMany(x => x.Family())) + { + await ValidatePageTreePageTabs(item); + } + + await AssertNoEventlogErrors(); + } + + private async Task ValidatePageTreePageTabs(PageTreeItem item) + { + var title = await item.TitleElement.TextContentAsync(); + await item.ClickAsync(); + await Debounce(); + foreach (var tab in new string[] { "Preview", "Content", "URLs", "Properties" }) + { + await page.Locator($"button[aria-label=\"{tab}\"]").ClickAsync(); + await Debounce(); + await Assertions.Expect(page.GetByText("error")).Not.ToBeVisibleAsync(); + await Assertions.Expect(page.GetByText("exception")).Not.ToBeVisibleAsync(); + } + } + + [Test] + public async Task Test00600_English_UK_Is_Populated() + { + await OpenAdminApplication("website Channel Example"); + await SelectTopDropdownLanguage("English (United Kingdom)"); + + var treeItems = await GetPageTreeItems(rootOnly: true); + foreach (var item in treeItems) + { + await item.ClickAsync(); + await Debounce(); + await Assertions.Expect(page.GetByText("This page does not exist in the current language")).ToHaveCountAsync(0); + } + } + + [Test] + public async Task Test00700_Spanish_Is_Not_Populated() + { + await OpenAdminApplication("website Channel Example"); + await SelectTopDropdownLanguage("Spanish"); + + var treeItems = await GetPageTreeItems(rootOnly: true); + foreach (var item in treeItems) + { + await item.ClickAsync(); + await Debounce(); + await Assertions.Expect(page.GetByText("This page does not exist in the current language")).ToHaveCountAsync(1); + } + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/03_ContentHubTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/03_ContentHubTests.cs new file mode 100644 index 0000000..ae66d7e --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/03_ContentHubTests.cs @@ -0,0 +1,93 @@ +using Microsoft.Playwright; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TestAfterMigration.Extensions; +using TestAfterMigration.Helpers; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace TestAfterMigration.Tests +{ + public class _03_ContentHubTests : AdminTestBase + { + [Test] + public async Task Test00100_Folder_With_Subfolder_Exists() + { + await OpenAdminApplication("Content hub"); + await SelectTopDropdownLanguage("English (United States)"); + + var folderDiv = page.Locator("div[class*=\"folder-view\"]"); + var parentFolder = folderDiv.GetByRole(AriaRole.Treeitem); + await Assertions.Expect(parentFolder).ToBeVisibleAsync(); + await parentFolder.GetByTestId("tree-item-expand").ClickAsync(); + await Debounce(); + await Assertions.Expect(parentFolder.GetByRole(AriaRole.Treeitem)).ToBeVisibleAsync(); + } + + [Test] + public async Task Test00200_Child_Folder_Contains_Item() + { + await OpenAdminApplication("Content hub"); + await SelectTopDropdownLanguage("English (United States)"); + + var folderDiv = page.Locator("div[class*=\"folder-view\"]"); + var parentFolder = folderDiv.GetByRole(AriaRole.Treeitem); + await Assertions.Expect(parentFolder).ToBeVisibleAsync(); + await parentFolder.GetByTestId("tree-item-expand").ClickAsync(); + var childFolder = parentFolder.GetByRole(AriaRole.Treeitem); + await childFolder.GetByTestId("tree-item-title").ClickAsync(); + await Debounce(); + await Assertions.Expect(page.GetByTestId("table-row")).ToBeVisibleAsync(); + } + + [Test] + public async Task Test00300_Draft_And_Scheduled_Items_Present() + { + await OpenAdminApplication("Content hub"); + await SelectTopDropdownLanguage("English (United States)"); + + await page.GetByLabel("All content items").ClickAsync(); + await Debounce(); + + await Assertions.Expect(page.GetByTestId("table-row").Filter(new LocatorFilterOptions { HasText = "Draft (Initial)" })).ToBeVisibleAsync(); + await Assertions.Expect(page.GetByTestId("table-row").Filter(new LocatorFilterOptions { HasText = "Scheduled" })).ToBeVisibleAsync(); + } + + [Test] + public async Task Test00400_No_Errors_When_Viewing_Tabs() + { + await OpenAdminApplication("Content hub"); + await SelectTopDropdownLanguage("English (United States)"); + + await page.GetByLabel("All content items").ClickAsync(); + await Debounce(); + + int count = await page.GetByTestId("table-row").CountAsync(); + for (int i = 0; i < count; i++) + { + var row = page.GetByTestId("table-row").Nth(i); + await row.ClickAsync(); + + await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Content$") }).ClickAsync(); + await Debounce(); + + await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Properties$") }).ClickAsync(); + await Debounce(); + + await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Usage$") }).ClickAsync(); + await Debounce(); + + await page.Locator("a").Filter(new LocatorFilterOptions { HasText = "List of content items" }).Nth(0).ClickAsync(); + await Debounce(); + } + + await AssertNoEventlogErrors(); + } + + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/04_MediaLibraryTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/04_MediaLibraryTests.cs new file mode 100644 index 0000000..006bc46 --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/04_MediaLibraryTests.cs @@ -0,0 +1,78 @@ +using Microsoft.Playwright; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Net.Http; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TestAfterMigration.Extensions; +using TestAfterMigration.Helpers; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace TestAfterMigration.Tests +{ + public class _04_MediaLibraryTests : AdminTestBase + { + [Test] + public async Task Test00100_Expected_Library_Structure_Was_Created() + { + await OpenAdminApplication("Media libraries"); + + await page.GetByTestId("table-row").ClickAsync(); // also checks that an item exists + await Debounce(); + + var topFolder = page.GetByRole(AriaRole.Treeitem).Nth(0); + await Assertions.Expect(topFolder).ToBeVisibleAsync(); + + var childFolder = topFolder.GetByRole(AriaRole.Treeitem).Nth(0); + await Assertions.Expect(childFolder).ToBeVisibleAsync(); + } + + [Test] + public async Task Test00200_Subfolder_Contains_2_Images() + { + await OpenAdminApplication("Media libraries"); + + await page.GetByTestId("table-row").ClickAsync(); // also checks that an item exists + await Debounce(); + + var topFolder = page.GetByRole(AriaRole.Treeitem).Nth(0); + var childFolder = topFolder.GetByRole(AriaRole.Treeitem).Nth(0); + + await childFolder.ClickAsync(); + await Debounce(); + + await Assertions.Expect(page.GetByTestId("asset-tile-preview")).ToHaveCountAsync(2); + } + + [Test] + public async Task Test00300_Subfolder_Images_Can_Be_Explored() + { + for (int i = 0; i < 2; i++) + { + await OpenAdminApplication("Media libraries"); + + await page.GetByTestId("table-row").ClickAsync(); // also checks that an item exists + await Debounce(); + + var topFolder = page.GetByRole(AriaRole.Treeitem).Nth(0); + var childFolder = topFolder.GetByRole(AriaRole.Treeitem).Nth(0); + + await childFolder.ClickAsync(); + await Debounce(); + + await page.GetByTestId("asset-tile-preview").Nth(i).ClickAsync(); + await Assertions.Expect(page.GetByTestId("FileName")).Not.ToBeEmptyAsync(); + await Assertions.Expect(page.GetByTestId("FileTitle")).Not.ToBeEmptyAsync(); + + string imageURL = $"{BaseURL}{await page.GetByTestId("MediaFileURL").Locator("a").GetAttributeAsync("href")}"; + var response = await new HttpClient().GetAsync(imageURL); + + Assert.That(response.IsSuccessStatusCode && response.Content.Headers.ContentType!.MediaType!.StartsWith("image")); + } + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/05_ChannelManagementTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/05_ChannelManagementTests.cs new file mode 100644 index 0000000..7aa4fcd --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/05_ChannelManagementTests.cs @@ -0,0 +1,72 @@ +using Microsoft.Playwright; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Net.Http; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TestAfterMigration.Extensions; +using TestAfterMigration.Helpers; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace TestAfterMigration.Tests +{ + public class _05_ChannelManagementTests : AdminTestBase + { + [Test] + public async Task Test00100_Email_Channel_Exists_And_Is_Explorable() + { + await OpenAdminApplication("Channel management"); + + await page.GetByTestId("table-cell-ChannelType").Filter(new LocatorFilterOptions { HasText = "Email" }).Nth(0).ClickAsync(); + await Debounce(); + + await Assertions.Expect(page.GetByTestId("ChannelDisplayName")).Not.ToBeEmptyAsync(); + await Assertions.Expect(page.GetByTestId("ChannelType")).Not.ToBeEmptyAsync(); + await Assertions.Expect(page.GetByTestId("ChannelSize")).Not.ToBeEmptyAsync(); + await Assertions.Expect(page.GetByTestId("EmailChannelSendingDomain")).Not.ToBeEmptyAsync(); + await Assertions.Expect(page.GetByTestId("EmailChannelServiceDomain")).Not.ToBeEmptyAsync(); + + await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^General$") }).ClickAsync(); + await Debounce(); + + await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Allowed content types$") }).ClickAsync(); + await Debounce(); + + await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Sender addresses$") }).ClickAsync(); + await Debounce(); + + await AssertNoEventlogErrors(); + } + + [Test] + public async Task Test00200_Website_Channel_Exists_And_Is_Explorable() + { + await OpenAdminApplication("Channel management"); + + await page.GetByTestId("table-cell-ChannelType").Filter(new LocatorFilterOptions { HasText = "Website" }).Nth(0).ClickAsync(); + await Debounce(); + + await Assertions.Expect(page.GetByTestId("ChannelDisplayName")).Not.ToBeEmptyAsync(); + await Assertions.Expect(page.GetByTestId("ChannelType")).Not.ToBeEmptyAsync(); + await Assertions.Expect(page.GetByTestId("ChannelSize")).Not.ToBeEmptyAsync(); + await Assertions.Expect(page.GetByTestId("WebsiteChannelDomain")).Not.ToBeEmptyAsync(); + await Assertions.Expect(page.GetByTestId("WebsiteChannelDomain")).Not.ToBeEmptyAsync(); + + await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^General$") }).ClickAsync(); + await Debounce(); + + await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Allowed content types$") }).ClickAsync(); + await Debounce(); + await Assertions.Expect(page.GetByTestId("table-row")).ToHaveCountAsync(1); + + await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Channel settings$") }).ClickAsync(); + await Debounce(); + + await AssertNoEventlogErrors(); + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/06_LanguageTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/06_LanguageTests.cs new file mode 100644 index 0000000..dca7353 --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/06_LanguageTests.cs @@ -0,0 +1,37 @@ +using Microsoft.Playwright; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Net.Http; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TestAfterMigration.Extensions; +using TestAfterMigration.Helpers; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace TestAfterMigration.Tests +{ + public class _06_LanguageTests : AdminTestBase + { + [Test] + public async Task Test00100_All_Expected_Languages_Present_And_Clickable_Without_Errors() + { + await OpenAdminApplication("Languages"); + + var expectedLanguages = new[] { "English - (default)", "English (United Kingdom)", "English (United States)", "Spanish" }; + + foreach (var lang in expectedLanguages) + { + await page.GetByTestId("table-cell-ContentLanguageDisplayName").Filter(new LocatorFilterOptions { HasText = lang }).Nth(0).ClickAsync(); + await Debounce(); + await page.GoBackAsync(); + await Debounce(); + } + + await AssertNoEventlogErrors(); + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/07_UserTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/07_UserTests.cs new file mode 100644 index 0000000..a632aae --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/07_UserTests.cs @@ -0,0 +1,30 @@ +using Microsoft.Playwright; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Net.Http; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TestAfterMigration.Extensions; +using TestAfterMigration.Helpers; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace TestAfterMigration.Tests +{ + public class _07_UserTests : AdminTestBase + { + [Test] + public async Task Test00100_sadmin_Explorable_Without_Errors() + { + await OpenAdminApplication("Users"); + + await page.GetByTestId("table-cell-UserName").Filter(new LocatorFilterOptions { HasText = "sadmin" }).Nth(0).ClickAsync(); + await Debounce(); + + await AssertNoEventlogErrors(); + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/08_ContentTypeTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/08_ContentTypeTests.cs new file mode 100644 index 0000000..90c8604 --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/08_ContentTypeTests.cs @@ -0,0 +1,37 @@ +using Microsoft.Playwright; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Net.Http; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TestAfterMigration.Extensions; +using TestAfterMigration.Helpers; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace TestAfterMigration.Tests +{ + public class _08_ContentTypeTests : AdminTestBase + { + [Test] + public async Task Test00100_Expected_Content_Types_Created_And_Explorable_Without_Errors() + { + await OpenAdminApplication("Content types"); + + var expectedTypes = new[] { "UMT.Event", "UMT.Faq", "UMT.Article" }; + + foreach (var lang in expectedTypes) + { + await page.GetByTestId("table-cell-ClassName").Filter(new LocatorFilterOptions { HasText = lang }).Nth(0).ClickAsync(); + await Debounce(); + await page.GoBackAsync(); + await Debounce(); + } + + await AssertNoEventlogErrors(); + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/09_TaxonomyTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/09_TaxonomyTests.cs new file mode 100644 index 0000000..3ac23de --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/09_TaxonomyTests.cs @@ -0,0 +1,46 @@ +using Microsoft.Playwright; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Net.Http; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TestAfterMigration.Extensions; +using TestAfterMigration.Helpers; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace TestAfterMigration.Tests +{ + public class _09_TaxonomyTests : AdminTestBase + { + [Test] + public async Task Test00100_Expected_Taxonomy_Structure_Created_And_Explorable() + { + await OpenAdminApplication("Taxonomies"); + + await page.GetByTestId("table-row").ClickAsync(); // also checks that an item exists + await Debounce(); + + await Assertions.Expect(page.GetByRole(AriaRole.Treeitem)).ToHaveCountAsync(3); + + var tagWithChildren = page.GetByRole(AriaRole.Treeitem).Nth(1); + await Assertions.Expect(tagWithChildren).ToBeVisibleAsync(); + + await tagWithChildren.GetByTestId("tree-item-expand").ClickAsync(); + await Debounce(); + + await Assertions.Expect(tagWithChildren.GetByRole(AriaRole.Treeitem)).ToHaveCountAsync(2); + + foreach (var item in await page.GetByRole(AriaRole.Treeitem).AllAsync()) + { + await item.ClickAsync(); + await Debounce(); + } + + await AssertNoEventlogErrors(); + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/AdminTestBase.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/AdminTestBase.cs new file mode 100644 index 0000000..9e63ee3 --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/AdminTestBase.cs @@ -0,0 +1,179 @@ + +using Microsoft.Playwright; +using TestAfterMigration.Enums; +using TestAfterMigration.Extensions; +using TestAfterMigration.Helpers; + +namespace TestAfterMigration.Tests +{ + public class AdminTestBase + { + protected IPlaywright playwright = null!; + protected IBrowser browser = null!; + protected IPage page = null!; + protected string BaseURL => Environment.GetEnvironmentVariable("BASE_URL") ?? ""; + protected string AdministratorUser => Environment.GetEnvironmentVariable("ADMINISTRATION_USER") ?? ""; + protected string AdministratorPassword => Environment.GetEnvironmentVariable("ADMINISTRATION_PASSWORD") ?? ""; + + [SetUp] + public async Task Setup() + { + playwright = await Playwright.CreateAsync(); + playwright.Selectors.SetTestIdAttribute("data-testid"); + + browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions + { + Headless = false, + }); + + page = await browser.NewPageAsync(); + await LoginAdmin(); + } + + [TearDown] + public async Task TearDown() + { + await page.CloseAsync(); + await browser.CloseAsync(); + } + + protected async Task LoginAdmin() + { + await page.GotoAsync($"{BaseURL}/admin"); + await Debounce(); + + if (await page.Locator("input[name='userName']").IsVisibleAsync()) + { + await page.FillAsync("input[name='userName']", AdministratorUser); + await page.FillAsync("input[name='password']", AdministratorPassword); + await page.ClickAsync("button[type='submit']"); + } + await Debounce(); + } + + /// + /// Consider using after calling this method based on complexity of concrete application page + /// + /// + /// + protected async Task OpenAdminApplication(string applicationName) + { + await LoginAdmin(); + await page.ClickAsync($"button[aria-label='{applicationName}']"); + await Debounce(); + } + + protected async Task SelectInAdminFormDropDown(string dropdownTitle, string itemTestID) + { + var dropdownArrow = page.Locator($":below(:text(\"{dropdownTitle}\"))[data-testid=\"xp-chevron-down\"]").First; + await dropdownArrow.ClickAsync(); + var item = page.GetByTestId(itemTestID); + await item.ClickAsync(); + } + + protected async Task> GetTableRows() + { + await page.WaitForLoadStateAsync(LoadState.NetworkIdle); + return await page.GetByRole(AriaRole.Row).AllAsync(); + } + + protected Task WaitForPageTreeLoaded() => page.GetByRole(AriaRole.Treeitem).WaitForVisible(); + + protected async Task> GetPageTreeItems(bool rootOnly = false) + { + await WaitForPageTreeLoaded(); + return await GetTreeNodeChildren(page.GetByRole(AriaRole.Treeitem).Nth(0), rootOnly, true); + } + + private async Task> GetTreeNodeChildren(ILocator parentNode, bool rootOnly, bool isChannelRoot) + { + var children = new List(); + var expand = parentNode.GetByTestId("tree-item-expand"); + bool scanSubChildren = !isChannelRoot && !rootOnly && await expand.IsVisibleAsync(); + + if (scanSubChildren) + { + await expand.ClickAsync(); + await parentNode.GetByRole(AriaRole.Treeitem).WaitForVisible(); + } + + foreach (var childLocator in (await parentNode.GetByRole(AriaRole.Treeitem).AllAsync())) + { + var item = new PageTreeItem(parentNode.Page, (await childLocator.GetAttributeAsync("data-testid-nodeid"))!); + await item.LoadInfo(); + children.Add(item); + } + + foreach (var child in children) + { + child.Children = await GetTreeNodeChildren(child.Locator, rootOnly, false); + } + return children.ToArray(); + } + + /// + /// Ensures all page loading processes have ended by monitoring that nothing more happens. + /// Duration is at least , so use only when needed if you + /// have a lot of tests. + /// + /// + /// + /// + protected async Task Debounce(int pollDelayMs = 100, int stableDelayMs = 500) + { + await page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); + var markupPrevious = ""; + var timerStart = DateTime.Now; + var isStable = false; + while (!isStable) + { + var markupCurrent = await page.ContentAsync(); + if (markupCurrent == markupPrevious) + { + var elapsed = (DateTime.Now - timerStart).TotalMilliseconds; + isStable = stableDelayMs <= elapsed; + } + else + { + markupPrevious = markupCurrent; + } + if (!isStable) await Task.Delay(pollDelayMs); + } + } + + protected async Task AssertNoEventlogErrors() + { + await OpenAdminApplication("Event log"); + + var logs = await GetEventLogRowsFirstPage(EventLogSeverity.Error); + + Assert.That(logs.Count == 0); + } + + private async Task> GetEventLogRowsFirstPage(EventLogSeverity severity) + { + if (await page.GetByText("There are no records to display").CountAsync() != 0) + { + return []; + } + await page.GetByTestId("filter-button").ClickAsync(); + + var severityOptionTestID = severity switch { EventLogSeverity.Info => "info", EventLogSeverity.Warning => "warning", EventLogSeverity.Error => "error", _ => throw new NotImplementedException() }; + + await SelectInAdminFormDropDown("Type", severityOptionTestID); + await page.GetByTestId("submit-button").ClickAsync(); + + await Debounce(); + + var rows = await GetTableRows(); + return rows; + } + + protected async Task SelectTopDropdownLanguage(string languageTitle) + { + await page.GetByTestId("LanguageSelector").ClickAsync(); + await page.GetByTestId("LanguageSelector").GetByTestId("menu-item").Filter(new LocatorFilterOptions { HasText = languageTitle }).ClickAsync(); + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/packages.lock.json b/tests/Kentico.Xperience.UMT.Tests/packages.lock.json new file mode 100644 index 0000000..0ecc96f --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/packages.lock.json @@ -0,0 +1,145 @@ +{ + "version": 2, + "dependencies": { + "net8.0": { + "coverlet.collector": { + "type": "Direct", + "requested": "[6.0.2, )", + "resolved": "6.0.2", + "contentHash": "bJShQ6uWRTQ100ZeyiMqcFlhP7WJ+bCuabUs885dJiBEzMsJMSFr7BOyeCw4rgvQokteGi5rKQTlkhfQPUXg2A==" + }, + "Microsoft.NET.Test.Sdk": { + "type": "Direct", + "requested": "[17.11.1, )", + "resolved": "17.11.1", + "contentHash": "U3Ty4BaGoEu+T2bwSko9tWqWUOU16WzSFkq6U8zve75oRBMSLTBdMAZrVNNz1Tq12aCdDom9fcOcM9QZaFHqFg==", + "dependencies": { + "Microsoft.CodeCoverage": "17.11.1", + "Microsoft.TestPlatform.TestHost": "17.11.1" + } + }, + "Microsoft.Playwright.NUnit": { + "type": "Direct", + "requested": "[1.47.0, )", + "resolved": "1.47.0", + "contentHash": "DOvKdrTiAX0S7kK9ppl5ZTa8lWvlChAiplxecNHrCbv3/g2CJCM3P3VFLHlU5/mvwuT7kT6VvblUPRGohLl70w==", + "dependencies": { + "Microsoft.NET.Test.Sdk": "16.11.0", + "Microsoft.Playwright": "1.47.0", + "Microsoft.Playwright.TestAdapter": "1.47.0", + "NUnit": "3.13.2", + "NUnit3TestAdapter": "4.0.0" + } + }, + "NUnit": { + "type": "Direct", + "requested": "[4.2.2, )", + "resolved": "4.2.2", + "contentHash": "mon0OPko28yZ/foVXrhiUvq1LReaGsBdziumyyYGxV/pOE4q92fuYeN+AF+gEU5pCjzykcdBt5l7xobTaiBjsg==" + }, + "NUnit.Analyzers": { + "type": "Direct", + "requested": "[4.3.0, )", + "resolved": "4.3.0", + "contentHash": "Ki4p1XrmnYil64HE9VkJSuo6KBr8vg7Mut43atYvItDp3HwIcRY5hi+n5o8GaX1IBCwYLaJgW5ZfZuBVPYXEkg==" + }, + "NUnit3TestAdapter": { + "type": "Direct", + "requested": "[4.6.0, )", + "resolved": "4.6.0", + "contentHash": "R7e1+a4vuV/YS+ItfL7f//rG+JBvVeVLX4mHzFEZo4W1qEKl8Zz27AqvQSAqo+BtIzUCo4aAJMYa56VXS4hudw==" + }, + "SonarAnalyzer.CSharp": { + "type": "Direct", + "requested": "[9.32.0.97167, )", + "resolved": "9.32.0.97167", + "contentHash": "Yxk86RV+8ynJpUhku1Yw2hITFmnmXKkXJ73cIFSy85ol5SnWREQg9RuTyV8nI7V7+pyLKpCfRmD7P0widsgjkg==" + }, + "Microsoft.CodeCoverage": { + "type": "Transitive", + "resolved": "17.11.1", + "contentHash": "nPJqrcA5iX+Y0kqoT3a+pD/8lrW/V7ayqnEJQsTonSoPz59J8bmoQhcSN4G8+UJ64Hkuf0zuxnfuj2lkHOq4cA==" + }, + "Microsoft.Playwright.TestAdapter": { + "type": "Transitive", + "resolved": "1.47.0", + "contentHash": "hKZPcPWknCYPSajPr16Xrwh0q3C7hx7GO2bmWLZ2uFMS3y+78UeBUBkMwMUJdtZRkHDtQGKRw7uPX8wEuOiDCw==", + "dependencies": { + "Microsoft.Playwright": "1.47.0", + "Microsoft.TestPlatform.ObjectModel": "17.3.0" + } + }, + "Microsoft.TestPlatform.ObjectModel": { + "type": "Transitive", + "resolved": "17.11.1", + "contentHash": "E2jZqAU6JeWEVsyOEOrSW1o1bpHLgb25ypvKNB/moBXPVsFYBPd/Jwi7OrYahG50J83LfHzezYI+GaEkpAotiA==", + "dependencies": { + "System.Reflection.Metadata": "1.6.0" + } + }, + "Microsoft.TestPlatform.TestHost": { + "type": "Transitive", + "resolved": "17.11.1", + "contentHash": "DnG+GOqJXO/CkoqlJWeDFTgPhqD/V6VqUIL3vINizCWZ3X+HshCtbbyDdSHQQEjrc2Sl/K3yaxX6s+5LFEdYuw==", + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "17.11.1", + "Newtonsoft.Json": "13.0.1" + } + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "System.ComponentModel.Annotations": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg==" + }, + "System.Reflection.Metadata": { + "type": "Transitive", + "resolved": "1.6.0", + "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==" + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "zaJsHfESQvJ11vbXnNlkrR46IaMULk/gHxYsJphzSF+07kTjPHv+Oc14w6QEOfo3Q4hqLJgStUaYB9DBl0TmWg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Text.Encodings.Web": "6.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "CentralTransitive", + "requested": "[9.0.0-rc.1.24431.7, )", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, + "Microsoft.Playwright": { + "type": "CentralTransitive", + "requested": "[1.47.0, )", + "resolved": "1.47.0", + "contentHash": "D9verOkoSO1vqqAe36jmuQlceEHd2leoYlLOXQkMuVDFTbhvblVk7LOm9LeS50u+5xNcIcJi1+vA2rZxN5tW4A==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0", + "System.ComponentModel.Annotations": "5.0.0", + "System.Text.Json": "6.0.0" + } + } + } + } +} \ No newline at end of file From c99f398af38fe0fba6e4075c31069a179ef08bb9 Mon Sep 17 00:00:00 2001 From: akfakmot Date: Thu, 3 Oct 2024 19:05:15 +0200 Subject: [PATCH 2/2] Resolve warnings throughout the solution Chore: Resolve warnings throughout the solution --- .../ServiceCollectionExtensions.cs | 11 +- .../Tests/06_LanguageTests.cs | 37 ------- .../Tests/07_UserTests.cs | 30 ----- .../Tests/08_ContentTypeTests.cs | 37 ------- .../Tests/AdminTestBase.cs | 103 ++++++++++-------- ...tlogTests.cs => Tests_01_EventlogTests.cs} | 2 +- ...annelTests.cs => Tests_02_ChannelTests.cs} | 79 ++++++-------- ...ubTests.cs => Tests_03_ContentHubTests.cs} | 38 +++---- ...braryTests.cs => Tests_04_MediaLibrary.cs} | 36 ++---- ....cs => Tests_05_ChannelManagementTests.cs} | 53 ++++----- .../Tests/Tests_06_Languages.cs | 25 +++++ .../Tests/Tests_07_Users.cs | 18 +++ .../Tests/Tests_08_ContentTypes.cs | 25 +++++ ..._TaxonomyTests.cs => Tests_09_Taxonomy.cs} | 22 +--- .../Helpers/SymbolXmlDocsWrapper.cs | 10 +- .../MdHelper.cs | 7 +- .../Kentico.Xperience.UMT.DocUtils/Program.cs | 8 +- .../Templates/ClassDocsViewModel.cs | 1 + .../Templates/UmtModelViewModel.cs | 1 + .../Walkers/ClassDocsVisitor.cs | 2 +- .../Walkers/Extensions.cs | 11 +- .../Walkers/UmtModelVisitor.cs | 28 ++--- .../Walkers/UmtModelWalker.cs | 2 +- 23 files changed, 259 insertions(+), 327 deletions(-) delete mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/06_LanguageTests.cs delete mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/07_UserTests.cs delete mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/08_ContentTypeTests.cs rename tests/Kentico.Xperience.UMT.Tests/Tests/{01_EventlogTests.cs => Tests_01_EventlogTests.cs} (74%) rename tests/Kentico.Xperience.UMT.Tests/Tests/{02_ChannelTests.cs => Tests_02_ChannelTests.cs} (64%) rename tests/Kentico.Xperience.UMT.Tests/Tests/{03_ContentHubTests.cs => Tests_03_ContentHubTests.cs} (69%) rename tests/Kentico.Xperience.UMT.Tests/Tests/{04_MediaLibraryTests.cs => Tests_04_MediaLibrary.cs} (61%) rename tests/Kentico.Xperience.UMT.Tests/Tests/{05_ChannelManagementTests.cs => Tests_05_ChannelManagementTests.cs} (53%) create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/Tests_06_Languages.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/Tests_07_Users.cs create mode 100644 tests/Kentico.Xperience.UMT.Tests/Tests/Tests_08_ContentTypes.cs rename tests/Kentico.Xperience.UMT.Tests/Tests/{09_TaxonomyTests.cs => Tests_09_Taxonomy.cs} (54%) diff --git a/examples/Kentico.Xperience.UMT.Example.AdminApp/ServiceCollectionExtensions.cs b/examples/Kentico.Xperience.UMT.Example.AdminApp/ServiceCollectionExtensions.cs index a802387..790b8af 100644 --- a/examples/Kentico.Xperience.UMT.Example.AdminApp/ServiceCollectionExtensions.cs +++ b/examples/Kentico.Xperience.UMT.Example.AdminApp/ServiceCollectionExtensions.cs @@ -180,12 +180,12 @@ async Task SendConfirmHeader() if (buffer[0] == 0x2D && buffer.Take(5).All(x => x.Equals(0X2D))) { - ms.Flush(); + await ms.FlushAsync(); break; } - ms.Write(data.Array!, data.Offset, receiveResult.Count); - ms.Flush(); + await ms.WriteAsync(data.Array!, data.Offset, receiveResult.Count); + await ms.FlushAsync(); int count = receiveResult.Count; totalReceived += count; @@ -236,6 +236,7 @@ async Task SendConfirmHeader() logService.LogException(SOURCE, "CONSUMER", e); } +#pragma warning disable S2589 if (socketAvailable) { await SendStats(stats); @@ -259,8 +260,8 @@ private static async Task ReceiveHeader(WebSocket webSocket) { var data = new ArraySegment(buffer); - ms.Write(data.Array!, data.Offset, receiveResult.Count); - ms.Flush(); + await ms.WriteAsync(data.Array!, data.Offset, receiveResult.Count); + await ms.FlushAsync(); } else { diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/06_LanguageTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/06_LanguageTests.cs deleted file mode 100644 index dca7353..0000000 --- a/tests/Kentico.Xperience.UMT.Tests/Tests/06_LanguageTests.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Microsoft.Playwright; -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Net.Http; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using TestAfterMigration.Extensions; -using TestAfterMigration.Helpers; -using static System.Runtime.InteropServices.JavaScript.JSType; - -namespace TestAfterMigration.Tests -{ - public class _06_LanguageTests : AdminTestBase - { - [Test] - public async Task Test00100_All_Expected_Languages_Present_And_Clickable_Without_Errors() - { - await OpenAdminApplication("Languages"); - - var expectedLanguages = new[] { "English - (default)", "English (United Kingdom)", "English (United States)", "Spanish" }; - - foreach (var lang in expectedLanguages) - { - await page.GetByTestId("table-cell-ContentLanguageDisplayName").Filter(new LocatorFilterOptions { HasText = lang }).Nth(0).ClickAsync(); - await Debounce(); - await page.GoBackAsync(); - await Debounce(); - } - - await AssertNoEventlogErrors(); - } - } -} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/07_UserTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/07_UserTests.cs deleted file mode 100644 index a632aae..0000000 --- a/tests/Kentico.Xperience.UMT.Tests/Tests/07_UserTests.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.Playwright; -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Net.Http; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using TestAfterMigration.Extensions; -using TestAfterMigration.Helpers; -using static System.Runtime.InteropServices.JavaScript.JSType; - -namespace TestAfterMigration.Tests -{ - public class _07_UserTests : AdminTestBase - { - [Test] - public async Task Test00100_sadmin_Explorable_Without_Errors() - { - await OpenAdminApplication("Users"); - - await page.GetByTestId("table-cell-UserName").Filter(new LocatorFilterOptions { HasText = "sadmin" }).Nth(0).ClickAsync(); - await Debounce(); - - await AssertNoEventlogErrors(); - } - } -} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/08_ContentTypeTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/08_ContentTypeTests.cs deleted file mode 100644 index 90c8604..0000000 --- a/tests/Kentico.Xperience.UMT.Tests/Tests/08_ContentTypeTests.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Microsoft.Playwright; -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Net.Http; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using TestAfterMigration.Extensions; -using TestAfterMigration.Helpers; -using static System.Runtime.InteropServices.JavaScript.JSType; - -namespace TestAfterMigration.Tests -{ - public class _08_ContentTypeTests : AdminTestBase - { - [Test] - public async Task Test00100_Expected_Content_Types_Created_And_Explorable_Without_Errors() - { - await OpenAdminApplication("Content types"); - - var expectedTypes = new[] { "UMT.Event", "UMT.Faq", "UMT.Article" }; - - foreach (var lang in expectedTypes) - { - await page.GetByTestId("table-cell-ClassName").Filter(new LocatorFilterOptions { HasText = lang }).Nth(0).ClickAsync(); - await Debounce(); - await page.GoBackAsync(); - await Debounce(); - } - - await AssertNoEventlogErrors(); - } - } -} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/AdminTestBase.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/AdminTestBase.cs index 9e63ee3..c2fc67c 100644 --- a/tests/Kentico.Xperience.UMT.Tests/Tests/AdminTestBase.cs +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/AdminTestBase.cs @@ -1,4 +1,6 @@ +using System.Diagnostics; + using Microsoft.Playwright; using TestAfterMigration.Enums; using TestAfterMigration.Extensions; @@ -8,45 +10,45 @@ namespace TestAfterMigration.Tests { public class AdminTestBase { - protected IPlaywright playwright = null!; - protected IBrowser browser = null!; - protected IPage page = null!; - protected string BaseURL => Environment.GetEnvironmentVariable("BASE_URL") ?? ""; - protected string AdministratorUser => Environment.GetEnvironmentVariable("ADMINISTRATION_USER") ?? ""; - protected string AdministratorPassword => Environment.GetEnvironmentVariable("ADMINISTRATION_PASSWORD") ?? ""; + protected IPlaywright Playwright = null!; + protected IBrowser Browser = null!; + protected IPage Page = null!; + protected static string BaseURL => Environment.GetEnvironmentVariable("BASE_URL") ?? ""; + protected static string AdministratorUser => Environment.GetEnvironmentVariable("ADMINISTRATION_USER") ?? ""; + protected static string AdministratorPassword => Environment.GetEnvironmentVariable("ADMINISTRATION_PASSWORD") ?? ""; [SetUp] public async Task Setup() { - playwright = await Playwright.CreateAsync(); - playwright.Selectors.SetTestIdAttribute("data-testid"); + Playwright = await Microsoft.Playwright.Playwright.CreateAsync(); + Playwright.Selectors.SetTestIdAttribute("data-testid"); - browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions + Browser = await Playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = false, }); - page = await browser.NewPageAsync(); + Page = await Browser.NewPageAsync(); await LoginAdmin(); } [TearDown] public async Task TearDown() { - await page.CloseAsync(); - await browser.CloseAsync(); + await Page.CloseAsync(); + await Browser.CloseAsync(); } protected async Task LoginAdmin() { - await page.GotoAsync($"{BaseURL}/admin"); + await Page.GotoAsync($"{BaseURL}/admin"); await Debounce(); - if (await page.Locator("input[name='userName']").IsVisibleAsync()) + if (await Page.Locator("input[name='userName']").IsVisibleAsync()) { - await page.FillAsync("input[name='userName']", AdministratorUser); - await page.FillAsync("input[name='password']", AdministratorPassword); - await page.ClickAsync("button[type='submit']"); + await Page.FillAsync("input[name='userName']", AdministratorUser); + await Page.FillAsync("input[name='password']", AdministratorPassword); + await Page.ClickAsync("button[type='submit']"); } await Debounce(); } @@ -59,30 +61,33 @@ protected async Task LoginAdmin() protected async Task OpenAdminApplication(string applicationName) { await LoginAdmin(); - await page.ClickAsync($"button[aria-label='{applicationName}']"); + await Page.ClickAsync($"button[aria-label='{applicationName}']"); await Debounce(); } - protected async Task SelectInAdminFormDropDown(string dropdownTitle, string itemTestID) + protected async Task SelectInAdminFormDropDown(string inputTestID, string[] itemTestIDs) { - var dropdownArrow = page.Locator($":below(:text(\"{dropdownTitle}\"))[data-testid=\"xp-chevron-down\"]").First; - await dropdownArrow.ClickAsync(); - var item = page.GetByTestId(itemTestID); - await item.ClickAsync(); + await Page.GetByTestId(inputTestID).ClickAsync(); + await Debounce(); + foreach (string itemTestID in itemTestIDs) + { + var item = Page.GetByTestId(itemTestID); + await item.ClickAsync(); + } } protected async Task> GetTableRows() { - await page.WaitForLoadStateAsync(LoadState.NetworkIdle); - return await page.GetByRole(AriaRole.Row).AllAsync(); + await Page.WaitForLoadStateAsync(LoadState.NetworkIdle); + return await Page.GetByRole(AriaRole.Row).AllAsync(); } - protected Task WaitForPageTreeLoaded() => page.GetByRole(AriaRole.Treeitem).WaitForVisible(); + protected Task WaitForPageTreeLoaded() => Page.GetByRole(AriaRole.Treeitem).WaitForVisible(); protected async Task> GetPageTreeItems(bool rootOnly = false) { await WaitForPageTreeLoaded(); - return await GetTreeNodeChildren(page.GetByRole(AriaRole.Treeitem).Nth(0), rootOnly, true); + return await GetTreeNodeChildren(Page.GetByRole(AriaRole.Treeitem).Nth(0), rootOnly, true); } private async Task> GetTreeNodeChildren(ILocator parentNode, bool rootOnly, bool isChannelRoot) @@ -121,24 +126,28 @@ private async Task> GetTreeNodeChildren(ILocator paren /// protected async Task Debounce(int pollDelayMs = 100, int stableDelayMs = 500) { - await page.WaitForLoadStateAsync(LoadState.NetworkIdle); - await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); - var markupPrevious = ""; - var timerStart = DateTime.Now; - var isStable = false; + await Page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await Page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); + string markupPrevious = ""; + var stopwatch = Stopwatch.StartNew(); + bool isStable = false; while (!isStable) { - var markupCurrent = await page.ContentAsync(); + string markupCurrent = await Page.ContentAsync(); if (markupCurrent == markupPrevious) { - var elapsed = (DateTime.Now - timerStart).TotalMilliseconds; + double elapsed = stopwatch.ElapsedMilliseconds; isStable = stableDelayMs <= elapsed; } else { markupPrevious = markupCurrent; + stopwatch.Restart(); + } + if (!isStable) + { + await Task.Delay(pollDelayMs); } - if (!isStable) await Task.Delay(pollDelayMs); } } @@ -153,27 +162,31 @@ protected async Task AssertNoEventlogErrors() private async Task> GetEventLogRowsFirstPage(EventLogSeverity severity) { - if (await page.GetByText("There are no records to display").CountAsync() != 0) + if (await Page.GetByText("There are no records to display").CountAsync() != 0) { return []; } - await page.GetByTestId("filter-button").ClickAsync(); + await SetFilter("Type", severity switch { EventLogSeverity.Info => "info", EventLogSeverity.Warning => "warning", EventLogSeverity.Error => "error", _ => throw new NotImplementedException() }); - var severityOptionTestID = severity switch { EventLogSeverity.Info => "info", EventLogSeverity.Warning => "warning", EventLogSeverity.Error => "error", _ => throw new NotImplementedException() }; + var rows = await GetTableRows(); + return rows; + } - await SelectInAdminFormDropDown("Type", severityOptionTestID); - await page.GetByTestId("submit-button").ClickAsync(); + protected async Task SetFilter(string inputTestID, params string[] optionTestID) + { + await Page.GetByTestId("filter-button").ClickAsync(); - await Debounce(); + await SelectInAdminFormDropDown(inputTestID, optionTestID); + await Page.GetByTestId("submit-button").ClickAsync(); - var rows = await GetTableRows(); - return rows; + await Debounce(); } protected async Task SelectTopDropdownLanguage(string languageTitle) { - await page.GetByTestId("LanguageSelector").ClickAsync(); - await page.GetByTestId("LanguageSelector").GetByTestId("menu-item").Filter(new LocatorFilterOptions { HasText = languageTitle }).ClickAsync(); + await Page.GetByTestId("LanguageSelector").ClickAsync(); + await Page.GetByTestId("LanguageSelector").GetByTestId("menu-item").Filter(new LocatorFilterOptions { HasText = languageTitle }).ClickAsync(); + await Debounce(); } } } diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/01_EventlogTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_01_EventlogTests.cs similarity index 74% rename from tests/Kentico.Xperience.UMT.Tests/Tests/01_EventlogTests.cs rename to tests/Kentico.Xperience.UMT.Tests/Tests/Tests_01_EventlogTests.cs index dd43ad0..8d6c7d3 100644 --- a/tests/Kentico.Xperience.UMT.Tests/Tests/01_EventlogTests.cs +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_01_EventlogTests.cs @@ -1,6 +1,6 @@ namespace TestAfterMigration.Tests { - public class _01_EventlogTests : AdminTestBase + public class Tests_01_EventlogTests : AdminTestBase { [Test] public async Task Test00100_EventlogHasNoErrors() => await AssertNoEventlogErrors(); diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/02_ChannelTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_02_ChannelTests.cs similarity index 64% rename from tests/Kentico.Xperience.UMT.Tests/Tests/02_ChannelTests.cs rename to tests/Kentico.Xperience.UMT.Tests/Tests/Tests_02_ChannelTests.cs index fb356a6..d2b5db2 100644 --- a/tests/Kentico.Xperience.UMT.Tests/Tests/02_ChannelTests.cs +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_02_ChannelTests.cs @@ -1,25 +1,17 @@ using Microsoft.Playwright; -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; using TestAfterMigration.Extensions; using TestAfterMigration.Helpers; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace TestAfterMigration.Tests { - public class _02_ChannelTests : AdminTestBase + public class Tests_02_ChannelTests : AdminTestBase { [Test] public async Task Test00100_Email_Channel_Was_Created() { await OpenAdminApplication("Channel management"); - await Assertions.Expect(page.GetByTestId("table-cell-ChannelDisplayName") + await Assertions.Expect(Page.GetByTestId("table-cell-ChannelDisplayName") .Filter(new LocatorFilterOptions { HasText = "email Channel Example" })) .ToHaveCountAsync(1); } @@ -28,7 +20,7 @@ await Assertions.Expect(page.GetByTestId("table-cell-ChannelDisplayName") public async Task Test00200_Web_Channel_Was_Created() { await OpenAdminApplication("Channel management"); - await Assertions.Expect(page.GetByTestId("table-cell-ChannelDisplayName") + await Assertions.Expect(Page.GetByTestId("table-cell-ChannelDisplayName") .Filter(new LocatorFilterOptions { HasText = "website Channel Example" })) .ToHaveCountAsync(1); } @@ -47,11 +39,11 @@ public async Task Test00300_Web_Channel_Has_Page_In_Different_Publish_States() { await item.ClickAsync(); await item.WaitBreadcrumbsLoaded(); - var status = await page.GetByTestId("breadcrumbs-status").TextContentAsync(); + string? status = await Page.GetByTestId("breadcrumbs-status").TextContentAsync(); pageStates.Add(status); } - foreach (var state in expectedStates) + foreach (string state in expectedStates) { Assert.That(pageStates.Contains(state, StringComparer.OrdinalIgnoreCase)); } @@ -63,10 +55,9 @@ public async Task Test00400_Web_Channel_Has_Page_With_Child() await OpenAdminApplication("website Channel Example"); await SelectTopDropdownLanguage("English (United States)"); - var pageStates = new HashSet(); var treeItems = await GetPageTreeItems(); - Assert.That(treeItems.Any(x => x.Children.Count() != 0)); + Assert.That(treeItems.Any(x => x.Children.Any())); } [Test] @@ -76,44 +67,44 @@ public async Task Test00400_New_Page_Create_And_Delete_Succeeds() await SelectTopDropdownLanguage("English (United States)"); string displayName = $"NewPage{Guid.NewGuid()}"; - await page.GetByTestId("create-page-button").ClickAsync(); - await page.GetByTestId("DisplayName").FillAsync(displayName); - await page.GetByTestId("content-item-action-button-confirmfirstselection").ClickAsync(); + await Page.GetByTestId("create-page-button").ClickAsync(); + await Page.GetByTestId("DisplayName").FillAsync(displayName); + await Page.GetByTestId("content-item-action-button-confirmfirstselection").ClickAsync(); - await page.GetByTestId("ArticleTitle").FillAsync("New Page"); + await Page.GetByTestId("ArticleTitle").FillAsync("New Page"); - await page.GetByTestId("ArticleDecimalNumberSample").FillAsync("123.456"); + await Page.GetByTestId("ArticleDecimalNumberSample").FillAsync("123.456"); - await page.GetByTestId("ArticleText").FillAsync("Text on\nmultiple\nlines".Replace("\n", Environment.NewLine)); + await Page.GetByTestId("ArticleText").FillAsync("Text on\nmultiple\nlines".Replace("\n", Environment.NewLine)); - await page.GetByTestId("file-input-upload").SetInputFilesAsync(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "Resources", "kentico_brand.png")); + await Page.GetByTestId("file-input-upload").SetInputFilesAsync(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "Resources", "kentico_brand.png")); - await page.GetByTestId("button-select-web-page").ClickAsync(); - await page.GetByTestId("table-row").Nth(1).ClickAsync(); - await page.GetByTestId("confirm-action").ClickAsync(); + await Page.GetByTestId("button-select-web-page").ClickAsync(); + await Page.GetByTestId("table-row").Nth(1).ClickAsync(); + await Page.GetByTestId("confirm-action").ClickAsync(); - await page.GetByTestId("button-select-existing-content-item").ClickAsync(); - await page.GetByTestId("table-row").Nth(0).ClickAsync(); - await page.GetByTestId("confirm-action").ClickAsync(); + await Page.GetByTestId("button-select-existing-content-item").ClickAsync(); + await Page.GetByTestId("table-row").Nth(0).ClickAsync(); + await Page.GetByTestId("confirm-action").ClickAsync(); - await page.GetByTestId("button-select-tag").ClickAsync(); - await page.GetByTestId("CoffeaTaxonomy.Select").GetByRole(AriaRole.Treeitem).Nth(0).ClickAsync(); - await page.GetByTestId("confirm-action").ClickAsync(); + await Page.GetByTestId("button-select-tag").ClickAsync(); + await Page.GetByTestId("CoffeaTaxonomy.Select").GetByRole(AriaRole.Treeitem).Nth(0).ClickAsync(); + await Page.GetByTestId("confirm-action").ClickAsync(); - await page.GetByTestId("content-item-menu-split-button-publish").ClickAsync(); - await page.GetByTestId("submit-form-button").ClickAsync(); + await Page.GetByTestId("content-item-menu-split-button-publish").ClickAsync(); + await Page.GetByTestId("submit-form-button").ClickAsync(); await Debounce(); - await page.GetByTestId("submit-form-button").ClickAsync(); + await Page.GetByTestId("submit-form-button").ClickAsync(); var treeItem = (await GetPageTreeItems(rootOnly: true)).First(x => x.Title == displayName); await ValidatePageTreePageTabs(treeItem); await treeItem.Locator.HoverAsync(); await treeItem.Locator.Locator("div[class*=\"trailing-cell\"]").ClickAsync(); - await page.GetByTestId("delete-action").ClickAsync(); - await page.GetByTestId("confirm-action").ClickAsync(); + await Page.GetByTestId("delete-action").ClickAsync(); + await Page.GetByTestId("confirm-action").ClickAsync(); - await Assertions.Expect(page.GetByText("successfully deleted").Nth(0)).ToBeVisibleAsync(); + await Assertions.Expect(Page.GetByText("successfully deleted").Nth(0)).ToBeVisibleAsync(); } [Test] @@ -122,7 +113,6 @@ public async Task Test00500_Web_Channel_No_Errors_When_Viewing_Tabs() await OpenAdminApplication("website Channel Example"); await SelectTopDropdownLanguage("English (United States)"); - var pageStates = new HashSet(); var treeItems = await GetPageTreeItems(); foreach (var item in treeItems.SelectMany(x => x.Family())) { @@ -134,15 +124,14 @@ public async Task Test00500_Web_Channel_No_Errors_When_Viewing_Tabs() private async Task ValidatePageTreePageTabs(PageTreeItem item) { - var title = await item.TitleElement.TextContentAsync(); await item.ClickAsync(); await Debounce(); - foreach (var tab in new string[] { "Preview", "Content", "URLs", "Properties" }) + foreach (string tab in new string[] { "Preview", "Content", "URLs", "Properties" }) { - await page.Locator($"button[aria-label=\"{tab}\"]").ClickAsync(); + await Page.Locator($"button[aria-label=\"{tab}\"]").ClickAsync(); await Debounce(); - await Assertions.Expect(page.GetByText("error")).Not.ToBeVisibleAsync(); - await Assertions.Expect(page.GetByText("exception")).Not.ToBeVisibleAsync(); + await Assertions.Expect(Page.GetByText("error")).Not.ToBeVisibleAsync(); + await Assertions.Expect(Page.GetByText("exception")).Not.ToBeVisibleAsync(); } } @@ -157,7 +146,7 @@ public async Task Test00600_English_UK_Is_Populated() { await item.ClickAsync(); await Debounce(); - await Assertions.Expect(page.GetByText("This page does not exist in the current language")).ToHaveCountAsync(0); + await Assertions.Expect(Page.GetByText("This page does not exist in the current language")).ToHaveCountAsync(0); } } @@ -172,7 +161,7 @@ public async Task Test00700_Spanish_Is_Not_Populated() { await item.ClickAsync(); await Debounce(); - await Assertions.Expect(page.GetByText("This page does not exist in the current language")).ToHaveCountAsync(1); + await Assertions.Expect(Page.GetByText("This page does not exist in the current language")).ToHaveCountAsync(1); } } } diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/03_ContentHubTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_03_ContentHubTests.cs similarity index 69% rename from tests/Kentico.Xperience.UMT.Tests/Tests/03_ContentHubTests.cs rename to tests/Kentico.Xperience.UMT.Tests/Tests/Tests_03_ContentHubTests.cs index ae66d7e..a7f1b9e 100644 --- a/tests/Kentico.Xperience.UMT.Tests/Tests/03_ContentHubTests.cs +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_03_ContentHubTests.cs @@ -1,19 +1,9 @@ using Microsoft.Playwright; -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Reflection; -using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; -using TestAfterMigration.Extensions; -using TestAfterMigration.Helpers; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace TestAfterMigration.Tests { - public class _03_ContentHubTests : AdminTestBase + public class Tests_03_ContentHubTests : AdminTestBase { [Test] public async Task Test00100_Folder_With_Subfolder_Exists() @@ -21,7 +11,7 @@ public async Task Test00100_Folder_With_Subfolder_Exists() await OpenAdminApplication("Content hub"); await SelectTopDropdownLanguage("English (United States)"); - var folderDiv = page.Locator("div[class*=\"folder-view\"]"); + var folderDiv = Page.Locator("div[class*=\"folder-view\"]"); var parentFolder = folderDiv.GetByRole(AriaRole.Treeitem); await Assertions.Expect(parentFolder).ToBeVisibleAsync(); await parentFolder.GetByTestId("tree-item-expand").ClickAsync(); @@ -35,14 +25,14 @@ public async Task Test00200_Child_Folder_Contains_Item() await OpenAdminApplication("Content hub"); await SelectTopDropdownLanguage("English (United States)"); - var folderDiv = page.Locator("div[class*=\"folder-view\"]"); + var folderDiv = Page.Locator("div[class*=\"folder-view\"]"); var parentFolder = folderDiv.GetByRole(AriaRole.Treeitem); await Assertions.Expect(parentFolder).ToBeVisibleAsync(); await parentFolder.GetByTestId("tree-item-expand").ClickAsync(); var childFolder = parentFolder.GetByRole(AriaRole.Treeitem); await childFolder.GetByTestId("tree-item-title").ClickAsync(); await Debounce(); - await Assertions.Expect(page.GetByTestId("table-row")).ToBeVisibleAsync(); + await Assertions.Expect(Page.GetByTestId("table-row")).ToBeVisibleAsync(); } [Test] @@ -51,11 +41,11 @@ public async Task Test00300_Draft_And_Scheduled_Items_Present() await OpenAdminApplication("Content hub"); await SelectTopDropdownLanguage("English (United States)"); - await page.GetByLabel("All content items").ClickAsync(); + await Page.GetByLabel("All content items").ClickAsync(); await Debounce(); - await Assertions.Expect(page.GetByTestId("table-row").Filter(new LocatorFilterOptions { HasText = "Draft (Initial)" })).ToBeVisibleAsync(); - await Assertions.Expect(page.GetByTestId("table-row").Filter(new LocatorFilterOptions { HasText = "Scheduled" })).ToBeVisibleAsync(); + await Assertions.Expect(Page.GetByTestId("table-row").Filter(new LocatorFilterOptions { HasText = "Draft (Initial)" })).ToBeVisibleAsync(); + await Assertions.Expect(Page.GetByTestId("table-row").Filter(new LocatorFilterOptions { HasText = "Scheduled" })).ToBeVisibleAsync(); } [Test] @@ -64,25 +54,25 @@ public async Task Test00400_No_Errors_When_Viewing_Tabs() await OpenAdminApplication("Content hub"); await SelectTopDropdownLanguage("English (United States)"); - await page.GetByLabel("All content items").ClickAsync(); + await Page.GetByLabel("All content items").ClickAsync(); await Debounce(); - int count = await page.GetByTestId("table-row").CountAsync(); + int count = await Page.GetByTestId("table-row").CountAsync(); for (int i = 0; i < count; i++) { - var row = page.GetByTestId("table-row").Nth(i); + var row = Page.GetByTestId("table-row").Nth(i); await row.ClickAsync(); - await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Content$") }).ClickAsync(); + await Page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Content$") }).ClickAsync(); await Debounce(); - await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Properties$") }).ClickAsync(); + await Page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Properties$") }).ClickAsync(); await Debounce(); - await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Usage$") }).ClickAsync(); + await Page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Usage$") }).ClickAsync(); await Debounce(); - await page.Locator("a").Filter(new LocatorFilterOptions { HasText = "List of content items" }).Nth(0).ClickAsync(); + await Page.Locator("a").Filter(new LocatorFilterOptions { HasText = "List of content items" }).Nth(0).ClickAsync(); await Debounce(); } diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/04_MediaLibraryTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_04_MediaLibrary.cs similarity index 61% rename from tests/Kentico.Xperience.UMT.Tests/Tests/04_MediaLibraryTests.cs rename to tests/Kentico.Xperience.UMT.Tests/Tests/Tests_04_MediaLibrary.cs index 006bc46..94d6779 100644 --- a/tests/Kentico.Xperience.UMT.Tests/Tests/04_MediaLibraryTests.cs +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_04_MediaLibrary.cs @@ -1,30 +1,18 @@ using Microsoft.Playwright; -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Net.Http; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using TestAfterMigration.Extensions; -using TestAfterMigration.Helpers; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace TestAfterMigration.Tests { - public class _04_MediaLibraryTests : AdminTestBase + public class Tests_04_MediaLibrary : AdminTestBase { [Test] public async Task Test00100_Expected_Library_Structure_Was_Created() { await OpenAdminApplication("Media libraries"); - await page.GetByTestId("table-row").ClickAsync(); // also checks that an item exists + await Page.GetByTestId("table-row").ClickAsync(); // also checks that an item exists await Debounce(); - var topFolder = page.GetByRole(AriaRole.Treeitem).Nth(0); + var topFolder = Page.GetByRole(AriaRole.Treeitem).Nth(0); await Assertions.Expect(topFolder).ToBeVisibleAsync(); var childFolder = topFolder.GetByRole(AriaRole.Treeitem).Nth(0); @@ -36,16 +24,16 @@ public async Task Test00200_Subfolder_Contains_2_Images() { await OpenAdminApplication("Media libraries"); - await page.GetByTestId("table-row").ClickAsync(); // also checks that an item exists + await Page.GetByTestId("table-row").ClickAsync(); // also checks that an item exists await Debounce(); - var topFolder = page.GetByRole(AriaRole.Treeitem).Nth(0); + var topFolder = Page.GetByRole(AriaRole.Treeitem).Nth(0); var childFolder = topFolder.GetByRole(AriaRole.Treeitem).Nth(0); await childFolder.ClickAsync(); await Debounce(); - await Assertions.Expect(page.GetByTestId("asset-tile-preview")).ToHaveCountAsync(2); + await Assertions.Expect(Page.GetByTestId("asset-tile-preview")).ToHaveCountAsync(2); } [Test] @@ -55,20 +43,20 @@ public async Task Test00300_Subfolder_Images_Can_Be_Explored() { await OpenAdminApplication("Media libraries"); - await page.GetByTestId("table-row").ClickAsync(); // also checks that an item exists + await Page.GetByTestId("table-row").ClickAsync(); // also checks that an item exists await Debounce(); - var topFolder = page.GetByRole(AriaRole.Treeitem).Nth(0); + var topFolder = Page.GetByRole(AriaRole.Treeitem).Nth(0); var childFolder = topFolder.GetByRole(AriaRole.Treeitem).Nth(0); await childFolder.ClickAsync(); await Debounce(); - await page.GetByTestId("asset-tile-preview").Nth(i).ClickAsync(); - await Assertions.Expect(page.GetByTestId("FileName")).Not.ToBeEmptyAsync(); - await Assertions.Expect(page.GetByTestId("FileTitle")).Not.ToBeEmptyAsync(); + await Page.GetByTestId("asset-tile-preview").Nth(i).ClickAsync(); + await Assertions.Expect(Page.GetByTestId("FileName")).Not.ToBeEmptyAsync(); + await Assertions.Expect(Page.GetByTestId("FileTitle")).Not.ToBeEmptyAsync(); - string imageURL = $"{BaseURL}{await page.GetByTestId("MediaFileURL").Locator("a").GetAttributeAsync("href")}"; + string imageURL = $"{BaseURL}{await Page.GetByTestId("MediaFileURL").Locator("a").GetAttributeAsync("href")}"; var response = await new HttpClient().GetAsync(imageURL); Assert.That(response.IsSuccessStatusCode && response.Content.Headers.ContentType!.MediaType!.StartsWith("image")); diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/05_ChannelManagementTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_05_ChannelManagementTests.cs similarity index 53% rename from tests/Kentico.Xperience.UMT.Tests/Tests/05_ChannelManagementTests.cs rename to tests/Kentico.Xperience.UMT.Tests/Tests/Tests_05_ChannelManagementTests.cs index 7aa4fcd..67d8219 100644 --- a/tests/Kentico.Xperience.UMT.Tests/Tests/05_ChannelManagementTests.cs +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_05_ChannelManagementTests.cs @@ -1,42 +1,31 @@ using Microsoft.Playwright; -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Net.Http; -using System.Reflection; -using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; -using TestAfterMigration.Extensions; -using TestAfterMigration.Helpers; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace TestAfterMigration.Tests { - public class _05_ChannelManagementTests : AdminTestBase + public class Tests_05_ChannelManagementTests : AdminTestBase { [Test] public async Task Test00100_Email_Channel_Exists_And_Is_Explorable() { await OpenAdminApplication("Channel management"); - await page.GetByTestId("table-cell-ChannelType").Filter(new LocatorFilterOptions { HasText = "Email" }).Nth(0).ClickAsync(); + await Page.GetByTestId("table-cell-ChannelType").Filter(new LocatorFilterOptions { HasText = "Email" }).Nth(0).ClickAsync(); await Debounce(); - await Assertions.Expect(page.GetByTestId("ChannelDisplayName")).Not.ToBeEmptyAsync(); - await Assertions.Expect(page.GetByTestId("ChannelType")).Not.ToBeEmptyAsync(); - await Assertions.Expect(page.GetByTestId("ChannelSize")).Not.ToBeEmptyAsync(); - await Assertions.Expect(page.GetByTestId("EmailChannelSendingDomain")).Not.ToBeEmptyAsync(); - await Assertions.Expect(page.GetByTestId("EmailChannelServiceDomain")).Not.ToBeEmptyAsync(); + await Assertions.Expect(Page.GetByTestId("ChannelDisplayName")).Not.ToBeEmptyAsync(); + await Assertions.Expect(Page.GetByTestId("ChannelType")).Not.ToBeEmptyAsync(); + await Assertions.Expect(Page.GetByTestId("ChannelSize")).Not.ToBeEmptyAsync(); + await Assertions.Expect(Page.GetByTestId("EmailChannelSendingDomain")).Not.ToBeEmptyAsync(); + await Assertions.Expect(Page.GetByTestId("EmailChannelServiceDomain")).Not.ToBeEmptyAsync(); - await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^General$") }).ClickAsync(); + await Page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^General$") }).ClickAsync(); await Debounce(); - await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Allowed content types$") }).ClickAsync(); + await Page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Allowed content types$") }).ClickAsync(); await Debounce(); - await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Sender addresses$") }).ClickAsync(); + await Page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Sender addresses$") }).ClickAsync(); await Debounce(); await AssertNoEventlogErrors(); @@ -47,23 +36,23 @@ public async Task Test00200_Website_Channel_Exists_And_Is_Explorable() { await OpenAdminApplication("Channel management"); - await page.GetByTestId("table-cell-ChannelType").Filter(new LocatorFilterOptions { HasText = "Website" }).Nth(0).ClickAsync(); + await Page.GetByTestId("table-cell-ChannelType").Filter(new LocatorFilterOptions { HasText = "Website" }).Nth(0).ClickAsync(); await Debounce(); - await Assertions.Expect(page.GetByTestId("ChannelDisplayName")).Not.ToBeEmptyAsync(); - await Assertions.Expect(page.GetByTestId("ChannelType")).Not.ToBeEmptyAsync(); - await Assertions.Expect(page.GetByTestId("ChannelSize")).Not.ToBeEmptyAsync(); - await Assertions.Expect(page.GetByTestId("WebsiteChannelDomain")).Not.ToBeEmptyAsync(); - await Assertions.Expect(page.GetByTestId("WebsiteChannelDomain")).Not.ToBeEmptyAsync(); + await Assertions.Expect(Page.GetByTestId("ChannelDisplayName")).Not.ToBeEmptyAsync(); + await Assertions.Expect(Page.GetByTestId("ChannelType")).Not.ToBeEmptyAsync(); + await Assertions.Expect(Page.GetByTestId("ChannelSize")).Not.ToBeEmptyAsync(); + await Assertions.Expect(Page.GetByTestId("WebsiteChannelDomain")).Not.ToBeEmptyAsync(); + await Assertions.Expect(Page.GetByTestId("WebsiteChannelDomain")).Not.ToBeEmptyAsync(); - await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^General$") }).ClickAsync(); + await Page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^General$") }).ClickAsync(); await Debounce(); - - await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Allowed content types$") }).ClickAsync(); + + await Page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Allowed content types$") }).ClickAsync(); await Debounce(); - await Assertions.Expect(page.GetByTestId("table-row")).ToHaveCountAsync(1); + await Assertions.Expect(Page.GetByTestId("table-row")).ToHaveCountAsync(1); - await page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Channel settings$") }).ClickAsync(); + await Page.GetByTestId("vertical-menu-item").Filter(new LocatorFilterOptions { HasTextRegex = new Regex("^Channel settings$") }).ClickAsync(); await Debounce(); await AssertNoEventlogErrors(); diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_06_Languages.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_06_Languages.cs new file mode 100644 index 0000000..702254e --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_06_Languages.cs @@ -0,0 +1,25 @@ +using Microsoft.Playwright; + +namespace TestAfterMigration.Tests +{ + public class Tests_06_Languages : AdminTestBase + { + [Test] + public async Task Test00100_All_Expected_Languages_Present_And_Clickable_Without_Errors() + { + await OpenAdminApplication("Languages"); + + string[] expectedLanguages = new[] { "English - (default)", "English (United Kingdom)", "English (United States)", "Spanish" }; + + foreach (string lang in expectedLanguages) + { + await Page.GetByTestId("table-cell-ContentLanguageDisplayName").Filter(new LocatorFilterOptions { HasText = lang }).Nth(0).ClickAsync(); + await Debounce(); + await Page.GoBackAsync(); + await Debounce(); + } + + await AssertNoEventlogErrors(); + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_07_Users.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_07_Users.cs new file mode 100644 index 0000000..7ae01ba --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_07_Users.cs @@ -0,0 +1,18 @@ +using Microsoft.Playwright; + +namespace TestAfterMigration.Tests +{ + public class Tests_07_Users : AdminTestBase + { + [Test] + public async Task Test00100_sadmin_Explorable_Without_Errors() + { + await OpenAdminApplication("Users"); + + await Page.GetByTestId("table-cell-UserName").Filter(new LocatorFilterOptions { HasText = "sadmin" }).Nth(0).ClickAsync(); + await Debounce(); + + await AssertNoEventlogErrors(); + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_08_ContentTypes.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_08_ContentTypes.cs new file mode 100644 index 0000000..ed2811f --- /dev/null +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_08_ContentTypes.cs @@ -0,0 +1,25 @@ +using Microsoft.Playwright; + +namespace TestAfterMigration.Tests +{ + public class Tests_08_ContentTypes : AdminTestBase + { + [Test] + public async Task Test00100_Expected_Content_Types_Created_And_Explorable_Without_Errors() + { + await OpenAdminApplication("Content types"); + + string[] expectedTypes = new[] { "UMT.Event", "UMT.Faq", "UMT.Article" }; + + foreach (string lang in expectedTypes) + { + await Page.GetByTestId("table-cell-ClassName").Filter(new LocatorFilterOptions { HasText = lang }).Nth(0).ClickAsync(); + await Debounce(); + await Page.GoBackAsync(); + await Debounce(); + } + + await AssertNoEventlogErrors(); + } + } +} diff --git a/tests/Kentico.Xperience.UMT.Tests/Tests/09_TaxonomyTests.cs b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_09_Taxonomy.cs similarity index 54% rename from tests/Kentico.Xperience.UMT.Tests/Tests/09_TaxonomyTests.cs rename to tests/Kentico.Xperience.UMT.Tests/Tests/Tests_09_Taxonomy.cs index 3ac23de..07775f2 100644 --- a/tests/Kentico.Xperience.UMT.Tests/Tests/09_TaxonomyTests.cs +++ b/tests/Kentico.Xperience.UMT.Tests/Tests/Tests_09_Taxonomy.cs @@ -1,32 +1,20 @@ using Microsoft.Playwright; -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Net.Http; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using TestAfterMigration.Extensions; -using TestAfterMigration.Helpers; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace TestAfterMigration.Tests { - public class _09_TaxonomyTests : AdminTestBase + public class Tests_09_Taxonomy : AdminTestBase { [Test] public async Task Test00100_Expected_Taxonomy_Structure_Created_And_Explorable() { await OpenAdminApplication("Taxonomies"); - await page.GetByTestId("table-row").ClickAsync(); // also checks that an item exists + await Page.GetByTestId("table-row").ClickAsync(); // also checks that an item exists await Debounce(); - await Assertions.Expect(page.GetByRole(AriaRole.Treeitem)).ToHaveCountAsync(3); + await Assertions.Expect(Page.GetByRole(AriaRole.Treeitem)).ToHaveCountAsync(3); - var tagWithChildren = page.GetByRole(AriaRole.Treeitem).Nth(1); + var tagWithChildren = Page.GetByRole(AriaRole.Treeitem).Nth(1); await Assertions.Expect(tagWithChildren).ToBeVisibleAsync(); await tagWithChildren.GetByTestId("tree-item-expand").ClickAsync(); @@ -34,7 +22,7 @@ public async Task Test00100_Expected_Taxonomy_Structure_Created_And_Explorable() await Assertions.Expect(tagWithChildren.GetByRole(AriaRole.Treeitem)).ToHaveCountAsync(2); - foreach (var item in await page.GetByRole(AriaRole.Treeitem).AllAsync()) + foreach (var item in await Page.GetByRole(AriaRole.Treeitem).AllAsync()) { await item.ClickAsync(); await Debounce(); diff --git a/utils/Kentico.Xperience.UMT.DocUtils/Helpers/SymbolXmlDocsWrapper.cs b/utils/Kentico.Xperience.UMT.DocUtils/Helpers/SymbolXmlDocsWrapper.cs index 14a8014..af95993 100644 --- a/utils/Kentico.Xperience.UMT.DocUtils/Helpers/SymbolXmlDocsWrapper.cs +++ b/utils/Kentico.Xperience.UMT.DocUtils/Helpers/SymbolXmlDocsWrapper.cs @@ -1,7 +1,9 @@ using System.Text.RegularExpressions; using System.Xml.Linq; using System.Xml.XPath; + using Kentico.Xperience.UMT.DocUtils.Walkers; + using Microsoft.CodeAnalysis; namespace Kentico.Xperience.UMT.DocUtils.Helpers; @@ -25,7 +27,7 @@ public bool TryGetSummary(out string summary) summary = DocsXml?.XPathSelectElement("//summary")?.Value?.Trim() ?? ""; return string.IsNullOrWhiteSpace(summary); } - + public string? GetSummaryOrEmpty() => DocsXml?.XPathSelectElement("//summary")?.Value?.Trim() ?? ""; public string? GetReturnsOrEmpty() => DocsXml?.XPathSelectElement("//returns")?.Value?.Trim() ?? ""; @@ -34,7 +36,7 @@ public bool TryGetSummary(out string summary) } -public class SymbolXmlDocsWrapperMarkdown:ISymbolXmlDocsWrapper +public class SymbolXmlDocsWrapperMarkdown : ISymbolXmlDocsWrapper { private readonly ISymbolXmlDocsWrapper inner; @@ -53,7 +55,7 @@ public bool TryGetSummary(out string summary) public string? GetParamSummaryOrEmpty(IParameterSymbol symbol) => ApplyFormattingPipeline(inner.GetParamSummaryOrEmpty(symbol)); - private string? ApplyFormattingPipeline(string? input) => HandleNewlines(input); + private static string? ApplyFormattingPipeline(string? input) => HandleNewlines(input); - private string? HandleNewlines(string? input) => input != null ? Regex.Replace(input, "([\r\n]{1,2})", "
") : null; + private static string? HandleNewlines(string? input) => input != null ? Regex.Replace(input, "([\r\n]{1,2})", "
") : null; } diff --git a/utils/Kentico.Xperience.UMT.DocUtils/MdHelper.cs b/utils/Kentico.Xperience.UMT.DocUtils/MdHelper.cs index ae5c779..c75efe4 100644 --- a/utils/Kentico.Xperience.UMT.DocUtils/MdHelper.cs +++ b/utils/Kentico.Xperience.UMT.DocUtils/MdHelper.cs @@ -1,5 +1,6 @@ using System.Collections.Concurrent; using System.Reflection; + using RazorLight; namespace Kentico.Xperience.UMT.DocUtils; @@ -8,18 +9,18 @@ public static class MdHelper { private static readonly ConcurrentDictionary> templates = new(); public static RazorLightEngine Engine { get; } - + static MdHelper() { var builder = new RazorLightEngineBuilder() .EnableDebugMode() .UseEmbeddedResourcesProject(typeof(MdHelper).Assembly, "Kentico.Xperience.UMT.DocUtils.Templates") .UseMemoryCachingProvider(); - + Engine = builder .Build(); } - + public static async Task RenderTemplate(string templateKey, TModel model) { try diff --git a/utils/Kentico.Xperience.UMT.DocUtils/Program.cs b/utils/Kentico.Xperience.UMT.DocUtils/Program.cs index 834f482..ae7472b 100644 --- a/utils/Kentico.Xperience.UMT.DocUtils/Program.cs +++ b/utils/Kentico.Xperience.UMT.DocUtils/Program.cs @@ -10,6 +10,7 @@ using Kentico.Xperience.UMT.DocUtils.Walkers; using Kentico.Xperience.UMT.Model; using Kentico.Xperience.UMT.Services; + using Microsoft.Build.Locator; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -18,6 +19,7 @@ using Microsoft.CodeAnalysis.MSBuild; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using NJsonSchema; const string projectNameKenticoXperienceUmt = "Kentico.Xperience.UMT"; @@ -45,7 +47,7 @@ break; } } - + throw new InvalidOperationException($"Incorrect number of parameters. Specify solution path as first argument and target documentation directory as second"); } } @@ -129,7 +131,7 @@ } } } - + var fcModel = formComponents.Select(x => new FormComponentTemplateModel(x.Key, x.Value.ToArray())).ToArray(); await MdHelper.RenderTemplateToFile("FormComponents", fcModel, markdownFilePath); } @@ -170,7 +172,7 @@ foreach (var solutionProject in solution.Projects) { Console.WriteLine($"Resolving project '{solutionProject.Name}'"); - + if (solutionProject.Name == projectNameKenticoXperienceUmt) { var compilation = await solutionProject.GetCompilationAsync(); diff --git a/utils/Kentico.Xperience.UMT.DocUtils/Templates/ClassDocsViewModel.cs b/utils/Kentico.Xperience.UMT.DocUtils/Templates/ClassDocsViewModel.cs index 2215028..5016f44 100644 --- a/utils/Kentico.Xperience.UMT.DocUtils/Templates/ClassDocsViewModel.cs +++ b/utils/Kentico.Xperience.UMT.DocUtils/Templates/ClassDocsViewModel.cs @@ -1,4 +1,5 @@ using Kentico.Xperience.UMT.Services; + using Microsoft.CodeAnalysis; namespace Kentico.Xperience.UMT.DocUtils.Templates; diff --git a/utils/Kentico.Xperience.UMT.DocUtils/Templates/UmtModelViewModel.cs b/utils/Kentico.Xperience.UMT.DocUtils/Templates/UmtModelViewModel.cs index d438dc0..b811474 100644 --- a/utils/Kentico.Xperience.UMT.DocUtils/Templates/UmtModelViewModel.cs +++ b/utils/Kentico.Xperience.UMT.DocUtils/Templates/UmtModelViewModel.cs @@ -1,4 +1,5 @@ using Kentico.Xperience.UMT.Examples; + using Microsoft.CodeAnalysis; namespace Kentico.Xperience.UMT.DocUtils.Templates; diff --git a/utils/Kentico.Xperience.UMT.DocUtils/Walkers/ClassDocsVisitor.cs b/utils/Kentico.Xperience.UMT.DocUtils/Walkers/ClassDocsVisitor.cs index e5d54eb..ecfb859 100644 --- a/utils/Kentico.Xperience.UMT.DocUtils/Walkers/ClassDocsVisitor.cs +++ b/utils/Kentico.Xperience.UMT.DocUtils/Walkers/ClassDocsVisitor.cs @@ -2,7 +2,7 @@ namespace Kentico.Xperience.UMT.DocUtils.Walkers; -public class ClassDocsVisitor: SymbolVisitor +public class ClassDocsVisitor : SymbolVisitor { public override void Visit(ISymbol? symbol) { diff --git a/utils/Kentico.Xperience.UMT.DocUtils/Walkers/Extensions.cs b/utils/Kentico.Xperience.UMT.DocUtils/Walkers/Extensions.cs index 260e8c3..147df39 100644 --- a/utils/Kentico.Xperience.UMT.DocUtils/Walkers/Extensions.cs +++ b/utils/Kentico.Xperience.UMT.DocUtils/Walkers/Extensions.cs @@ -1,4 +1,5 @@ using System.Xml.Linq; + using Microsoft.CodeAnalysis; namespace Kentico.Xperience.UMT.DocUtils.Walkers; @@ -15,8 +16,8 @@ public static class Extensions return null; } - public delegate bool BaseTypePredicate(INamedTypeSymbol symbol); - + public delegate bool BaseTypePredicate(INamedTypeSymbol symbol); + public static INamedTypeSymbol? GetFirstBaseType(this INamedTypeSymbol symbol, BaseTypePredicate predicate) { var baseType = symbol.BaseType; @@ -26,11 +27,11 @@ public static class Extensions { return baseType; } - baseType = baseType?.BaseType; + baseType = baseType.BaseType; } return null; } - + public static INamedTypeSymbol? GetFirstBaseTypeOrSelf(this INamedTypeSymbol symbol, BaseTypePredicate predicate) => predicate(symbol) ? symbol @@ -48,4 +49,4 @@ public static bool IsAccessibleOutsideOfAssembly(this ISymbol symbol) => Accessibility.Public => true, _ => true, //Here should be some reasonable default }; -} \ No newline at end of file +} diff --git a/utils/Kentico.Xperience.UMT.DocUtils/Walkers/UmtModelVisitor.cs b/utils/Kentico.Xperience.UMT.DocUtils/Walkers/UmtModelVisitor.cs index aabc70f..c4a5273 100644 --- a/utils/Kentico.Xperience.UMT.DocUtils/Walkers/UmtModelVisitor.cs +++ b/utils/Kentico.Xperience.UMT.DocUtils/Walkers/UmtModelVisitor.cs @@ -1,15 +1,17 @@ using System.Xml.Linq; using System.Xml.XPath; + using Kentico.Xperience.UMT.Attributes; using Kentico.Xperience.UMT.DocUtils.Helpers; using Kentico.Xperience.UMT.DocUtils.Templates; using Kentico.Xperience.UMT.Examples; using Kentico.Xperience.UMT.Services; + using Microsoft.CodeAnalysis; namespace Kentico.Xperience.UMT.DocUtils.Walkers; -public class UmtModelVisitor: SymbolVisitor +public class UmtModelVisitor : SymbolVisitor { private readonly IImportService importService; @@ -27,13 +29,13 @@ public override void VisitNamedType(INamedTypeSymbol symbol) var sampleInfo = SampleProvider.GetSerializedSample(sample.Value, importService); if (sampleInfo != null) { - sampleList.Add(sampleInfo); + sampleList.Add(sampleInfo); } } - + var docs = new SymbolXmlDocsWrapperMarkdown(new SymbolXmlDocsWrapper(symbol)); ModelClasses.Add(new ModelClass(symbol, symbol.Name, docs.GetSummaryOrEmpty() ?? "", new List(), sampleList)); - + foreach (var member in symbol.GetMembers()) { member.Accept(this); @@ -48,14 +50,14 @@ public override void VisitField(IFieldSymbol symbol) { var modelClass = ModelClasses.Find(x => symbol.ContainingSymbol?.Equals(x.Symbol, SymbolEqualityComparer.IncludeNullability) == true) ?? throw new InvalidOperationException("DISCRIMINATOR exists but class not found => this is possibly error in tool"); - + if (symbol.Name == "DISCRIMINATOR") { ModelClasses[ModelClasses.IndexOf(modelClass)] = modelClass with { Discriminator = symbol.ConstantValue as string }; - } + } } base.VisitField(symbol); @@ -67,7 +69,7 @@ public override void VisitProperty(IPropertySymbol symbol) var docRefs = symbol.GetDocumentationXml()? .XPathSelectElements("//docref") - .Select(x=> new DocRef(x.Attribute("uri")?.Value, x.Attribute("header")?.Value, x.Value)) + .Select(x => new DocRef(x.Attribute("uri")?.Value, x.Attribute("header")?.Value, x.Value)) .ToArray() ?? Array.Empty(); string? summary = docs.GetSummaryOrEmpty(); @@ -77,10 +79,10 @@ public override void VisitProperty(IPropertySymbol symbol) { summary += " "; } - summary += $"{string.Join(", ", docRefs.Select(x => x.ToMarkdownLink()))}"; + summary += $"{string.Join(", ", docRefs.Select(x => x.ToMarkdownLink()))}"; } - - + + bool isUniqueId = false; ModelPropertyReference? reference = null; var validationInfo = new ValidationInfo(false); @@ -115,12 +117,12 @@ public override void VisitProperty(IPropertySymbol symbol) typeArgument.Accept(this); } } - + if (TestIfTypeBelongToUmt(symbol.Type)) { symbol.Type.Accept(this); } - + base.VisitProperty(symbol); } @@ -185,5 +187,5 @@ private static ModelPropertyReference ReadReferencePropertyInfo(AttributeData at ); } - private bool TestIfTypeBelongToUmt(ITypeSymbol symbol) => symbol.ContainingNamespace.ToDisplayString().Contains("Kentico.Xperience.UMT"); + private static bool TestIfTypeBelongToUmt(ITypeSymbol symbol) => symbol.ContainingNamespace.ToDisplayString().Contains("Kentico.Xperience.UMT"); } diff --git a/utils/Kentico.Xperience.UMT.DocUtils/Walkers/UmtModelWalker.cs b/utils/Kentico.Xperience.UMT.DocUtils/Walkers/UmtModelWalker.cs index e1a1747..8881efc 100644 --- a/utils/Kentico.Xperience.UMT.DocUtils/Walkers/UmtModelWalker.cs +++ b/utils/Kentico.Xperience.UMT.DocUtils/Walkers/UmtModelWalker.cs @@ -4,7 +4,7 @@ namespace Kentico.Xperience.UMT.DocUtils.Walkers; -public class UmtModelWalker: CSharpSyntaxWalker +public class UmtModelWalker : CSharpSyntaxWalker { private readonly List umtModelClasses = new(); public List UmtModelClasses => umtModelClasses;