From 562f7e9e373b1e884dcccf2bb179524fe7c2d7de Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 6 Feb 2026 18:44:40 -0500 Subject: [PATCH] Migrate Playwright suite to .NET UI tests and deprecate TS project --- NEW/JdeScoping.slnx | 1 + .../JdeScoping.Ui.Tests/AuthApiSmokeTests.cs | 38 +++++ .../ComponentLotSearchTests.cs | 17 ++ .../JdeScoping.Ui.Tests/DataSyncPageTests.cs | 34 ++++ NEW/tests/JdeScoping.Ui.Tests/GlobalUsings.cs | 2 + .../Helpers/UiAuthHelper.cs | 53 +++++++ .../Helpers/UiNavigationHelper.cs | 106 +++++++++++++ .../Helpers/UiSearchFormHelper.cs | 63 ++++++++ .../JdeScoping.Ui.Tests.csproj | 32 ++++ .../JdeScoping.Ui.Tests/LoginPageTests.cs | 30 ++++ NEW/tests/JdeScoping.Ui.Tests/README.md | 29 ++++ .../RefreshStatusPageTests.cs | 30 ++++ .../JdeScoping.Ui.Tests/SearchPageTests.cs | 20 +++ .../SearchQueuePageTests.cs | 33 ++++ .../SearchesDashboardPageTests.cs | 28 ++++ .../Support/PlaywrightFixture.cs | 31 ++++ .../Support/SearchFlowTestBase.cs | 56 +++++++ .../Support/TestDataPaths.cs | 6 + .../Support/UiSearchTypes.cs | 21 +++ .../JdeScoping.Ui.Tests/Support/UiTestBase.cs | 29 ++++ .../Support/UiTestCollection.cs | 9 ++ .../Support/UiTestSettings.cs | 11 ++ .../TestData}/empty_file.xlsx | Bin .../TestData}/invalid_format.txt | 0 .../TestData}/invalid_workorders.xlsx | Bin .../TestData}/max_workorders.xlsx | Bin .../TestData}/multiple_items.xlsx | Bin .../TestData}/multiple_lots.xlsx | Bin .../TestData}/multiple_operations.xlsx | Bin .../TestData}/multiple_workorders.xlsx | Bin .../TestData}/single_item.xlsx | Bin .../TestData}/single_lot.xlsx | Bin .../TestData}/single_operation.xlsx | Bin .../TestData}/single_workorder.xlsx | Bin .../TestData}/special_chars_workorders.xlsx | Bin .../TestData}/test-data.json | 0 .../TimeSpanItemNumberSearchTests.cs | 19 +++ .../TimeSpanOperatorSearchTests.cs | 18 +++ .../TimeSpanPcExtractMisSearchTests.cs | 18 +++ .../TimeSpanPcItemSearchTests.cs | 21 +++ .../TimeSpanPcOperatorSearchTests.cs | 19 +++ .../TimeSpanPcPartOpSearchTests.cs | 21 +++ .../TimeSpanPcWoPartOpSearchTests.cs | 22 +++ .../TimeSpanProfitCenterSearchTests.cs | 18 +++ .../TimeSpanWcExtractMisSearchTests.cs | 18 +++ .../TimeSpanWcItemSearchTests.cs | 21 +++ .../TimeSpanWcOperatorSearchTests.cs | 19 +++ .../TimeSpanWcPartOpSearchTests.cs | 21 +++ .../TimeSpanWcWoPartOpSearchTests.cs | 22 +++ .../TimeSpanWorkCenterSearchTests.cs | 18 +++ .../WorkOrderSearchTests.cs | 17 ++ .../{ => deprecated}/playwright/README.md | 0 .../playwright/debug-screenshot.png | Bin .../playwright/fixtures/test.fixture.ts | 0 .../playwright/helpers/auth.helper.ts | 0 .../playwright/helpers/autocomplete.helper.ts | 0 .../playwright/helpers/date-picker.helper.ts | 0 .../playwright/helpers/file-upload.helper.ts | 0 .../playwright/helpers/index.ts | 0 .../playwright/helpers/navigation.helper.ts | 0 .../playwright/helpers/radzen.helper.ts | 0 .../playwright/helpers/search-type.helper.ts | 0 .../playwright/helpers/validation.helper.ts | 0 .../playwright/package-lock.json | 0 .../{ => deprecated}/playwright/package.json | 0 .../playwright/playwright-report/index.html | 0 .../playwright/playwright.config.ts | 0 .../playwright/scripts/create-test-excel.js | 0 .../playwright/test-data/empty_file.xlsx | Bin 0 -> 6396 bytes .../playwright/test-data/invalid_format.txt | 2 + .../test-data/invalid_workorders.xlsx | Bin 0 -> 6458 bytes .../playwright/test-data/max_workorders.xlsx | Bin 0 -> 6543 bytes .../playwright/test-data/multiple_items.xlsx | Bin 0 -> 6445 bytes .../playwright/test-data/multiple_lots.xlsx | Bin 0 -> 6469 bytes .../test-data/multiple_operations.xlsx | Bin 0 -> 6522 bytes .../test-data/multiple_workorders.xlsx | Bin 0 -> 6458 bytes .../playwright/test-data/single_item.xlsx | Bin 0 -> 6421 bytes .../playwright/test-data/single_lot.xlsx | Bin 0 -> 6447 bytes .../test-data/single_operation.xlsx | Bin 0 -> 6488 bytes .../test-data/single_workorder.xlsx | Bin 0 -> 6413 bytes .../test-data/special_chars_workorders.xlsx | Bin 0 -> 6466 bytes .../playwright/test-data/test-data.json | 146 ++++++++++++++++++ .../playwright/test-results/.last-run.json | 0 .../playwright/tests/component-lot.spec.ts | 0 .../playwright/tests/data-sync.spec.ts | 0 .../playwright/tests/login.spec.ts | 0 .../playwright/tests/refresh-status.spec.ts | 0 .../playwright/tests/search-page.spec.ts | 0 .../playwright/tests/search-queue.spec.ts | 0 .../tests/searches-dashboard.spec.ts | 0 .../tests/timespan-item-number.spec.ts | 0 .../tests/timespan-operator.spec.ts | 0 .../tests/timespan-pc-extractmis.spec.ts | 0 .../playwright/tests/timespan-pc-item.spec.ts | 0 .../tests/timespan-pc-operator.spec.ts | 0 .../tests/timespan-pc-partop.spec.ts | 0 .../tests/timespan-pc-wo-partop.spec.ts | 0 .../tests/timespan-profit-center.spec.ts | 0 .../tests/timespan-wc-extractmis.spec.ts | 0 .../playwright/tests/timespan-wc-item.spec.ts | 0 .../tests/timespan-wc-operator.spec.ts | 0 .../tests/timespan-wc-partop.spec.ts | 0 .../tests/timespan-wc-wo-partop.spec.ts | 0 .../tests/timespan-work-center.spec.ts | 0 .../playwright/tests/work-order.spec.ts | 0 105 files changed, 1119 insertions(+) create mode 100644 NEW/tests/JdeScoping.Ui.Tests/AuthApiSmokeTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/ComponentLotSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/DataSyncPageTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/GlobalUsings.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/Helpers/UiAuthHelper.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/Helpers/UiNavigationHelper.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/Helpers/UiSearchFormHelper.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/JdeScoping.Ui.Tests.csproj create mode 100644 NEW/tests/JdeScoping.Ui.Tests/LoginPageTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/README.md create mode 100644 NEW/tests/JdeScoping.Ui.Tests/RefreshStatusPageTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/SearchPageTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/SearchQueuePageTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/SearchesDashboardPageTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/Support/PlaywrightFixture.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/Support/SearchFlowTestBase.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/Support/TestDataPaths.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/Support/UiSearchTypes.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/Support/UiTestBase.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/Support/UiTestCollection.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/Support/UiTestSettings.cs rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/empty_file.xlsx (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/invalid_format.txt (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/invalid_workorders.xlsx (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/max_workorders.xlsx (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/multiple_items.xlsx (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/multiple_lots.xlsx (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/multiple_operations.xlsx (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/multiple_workorders.xlsx (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/single_item.xlsx (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/single_lot.xlsx (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/single_operation.xlsx (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/single_workorder.xlsx (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/special_chars_workorders.xlsx (100%) rename {TestScripts/playwright/test-data => NEW/tests/JdeScoping.Ui.Tests/TestData}/test-data.json (100%) create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanItemNumberSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanOperatorSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcExtractMisSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcItemSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcOperatorSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcPartOpSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcWoPartOpSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanProfitCenterSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcExtractMisSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcItemSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcOperatorSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcPartOpSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcWoPartOpSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/TimeSpanWorkCenterSearchTests.cs create mode 100644 NEW/tests/JdeScoping.Ui.Tests/WorkOrderSearchTests.cs rename TestScripts/{ => deprecated}/playwright/README.md (100%) rename TestScripts/{ => deprecated}/playwright/debug-screenshot.png (100%) rename TestScripts/{ => deprecated}/playwright/fixtures/test.fixture.ts (100%) rename TestScripts/{ => deprecated}/playwright/helpers/auth.helper.ts (100%) rename TestScripts/{ => deprecated}/playwright/helpers/autocomplete.helper.ts (100%) rename TestScripts/{ => deprecated}/playwright/helpers/date-picker.helper.ts (100%) rename TestScripts/{ => deprecated}/playwright/helpers/file-upload.helper.ts (100%) rename TestScripts/{ => deprecated}/playwright/helpers/index.ts (100%) rename TestScripts/{ => deprecated}/playwright/helpers/navigation.helper.ts (100%) rename TestScripts/{ => deprecated}/playwright/helpers/radzen.helper.ts (100%) rename TestScripts/{ => deprecated}/playwright/helpers/search-type.helper.ts (100%) rename TestScripts/{ => deprecated}/playwright/helpers/validation.helper.ts (100%) rename TestScripts/{ => deprecated}/playwright/package-lock.json (100%) rename TestScripts/{ => deprecated}/playwright/package.json (100%) rename TestScripts/{ => deprecated}/playwright/playwright-report/index.html (100%) rename TestScripts/{ => deprecated}/playwright/playwright.config.ts (100%) rename TestScripts/{ => deprecated}/playwright/scripts/create-test-excel.js (100%) create mode 100644 TestScripts/deprecated/playwright/test-data/empty_file.xlsx create mode 100644 TestScripts/deprecated/playwright/test-data/invalid_format.txt create mode 100644 TestScripts/deprecated/playwright/test-data/invalid_workorders.xlsx create mode 100644 TestScripts/deprecated/playwright/test-data/max_workorders.xlsx create mode 100644 TestScripts/deprecated/playwright/test-data/multiple_items.xlsx create mode 100644 TestScripts/deprecated/playwright/test-data/multiple_lots.xlsx create mode 100644 TestScripts/deprecated/playwright/test-data/multiple_operations.xlsx create mode 100644 TestScripts/deprecated/playwright/test-data/multiple_workorders.xlsx create mode 100644 TestScripts/deprecated/playwright/test-data/single_item.xlsx create mode 100644 TestScripts/deprecated/playwright/test-data/single_lot.xlsx create mode 100644 TestScripts/deprecated/playwright/test-data/single_operation.xlsx create mode 100644 TestScripts/deprecated/playwright/test-data/single_workorder.xlsx create mode 100644 TestScripts/deprecated/playwright/test-data/special_chars_workorders.xlsx create mode 100644 TestScripts/deprecated/playwright/test-data/test-data.json rename TestScripts/{ => deprecated}/playwright/test-results/.last-run.json (100%) rename TestScripts/{ => deprecated}/playwright/tests/component-lot.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/data-sync.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/login.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/refresh-status.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/search-page.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/search-queue.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/searches-dashboard.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-item-number.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-operator.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-pc-extractmis.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-pc-item.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-pc-operator.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-pc-partop.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-pc-wo-partop.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-profit-center.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-wc-extractmis.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-wc-item.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-wc-operator.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-wc-partop.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-wc-wo-partop.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/timespan-work-center.spec.ts (100%) rename TestScripts/{ => deprecated}/playwright/tests/work-order.spec.ts (100%) diff --git a/NEW/JdeScoping.slnx b/NEW/JdeScoping.slnx index 6c0e274..3a8b38c 100644 --- a/NEW/JdeScoping.slnx +++ b/NEW/JdeScoping.slnx @@ -28,6 +28,7 @@ + diff --git a/NEW/tests/JdeScoping.Ui.Tests/AuthApiSmokeTests.cs b/NEW/tests/JdeScoping.Ui.Tests/AuthApiSmokeTests.cs new file mode 100644 index 0000000..61dce19 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/AuthApiSmokeTests.cs @@ -0,0 +1,38 @@ +using System.Net; +using System.Net.Http.Json; +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; +using JdeScoping.Core.Models; +using JdeScoping.Core.Models.Auth; +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public class AuthApiSmokeTests +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public async Task AuthApi_Login_WorksAgainstDockerHost() + { + var cookies = new CookieContainer(); + using var handler = new HttpClientHandler { CookieContainer = cookies }; + using var client = new HttpClient(handler) { BaseAddress = new Uri(UiTestSettings.BaseUrl) }; + + var key = await client.GetFromJsonAsync("api/auth/public-key"); + Assert.NotNull(key); + Assert.Contains("BEGIN PUBLIC KEY", key!.PublicKeyPem); + + var payload = JsonSerializer.Serialize(new LoginModel { Username = "testuser", Password = "testpass" }); + + using var rsa = RSA.Create(); + rsa.ImportFromPem(key.PublicKeyPem); + var encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes(payload), RSAEncryptionPadding.OaepSHA256); + + var login = await client.PostAsJsonAsync("api/auth/login", new EncryptedLoginRequest(Convert.ToBase64String(encrypted))); + Assert.Equal(HttpStatusCode.OK, login.StatusCode); + + var me = await client.GetAsync("api/auth/me"); + Assert.Equal(HttpStatusCode.OK, me.StatusCode); + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/ComponentLotSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/ComponentLotSearchTests.cs new file mode 100644 index 0000000..0164f07 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/ComponentLotSearchTests.cs @@ -0,0 +1,17 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class ComponentLotSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task ComponentLot_SubmitsWithUploadedWorkbook() => + RunSearchSubmissionAsync( + UiSearchTypes.ComponentLot, + "MIGRATED-TC-020", + uploads: + [ + ("Filter By Component Lot", "single_lot.xlsx") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/DataSyncPageTests.cs b/NEW/tests/JdeScoping.Ui.Tests/DataSyncPageTests.cs new file mode 100644 index 0000000..f23f303 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/DataSyncPageTests.cs @@ -0,0 +1,34 @@ +using JdeScoping.Ui.Tests.Helpers; +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class DataSyncPageTests(PlaywrightFixture fixture) : UiTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public async Task DataSync_Loads() + { + await RunAsync(async page => + { + await UiNavigationHelper.NavigateToDataSyncAsync(page); + var url = page.Url; + var onDataSync = url.EndsWith("/data-sync/requests", StringComparison.OrdinalIgnoreCase); + var redirectedToSearch = url.EndsWith("/search", StringComparison.OrdinalIgnoreCase); + Assert.True(onDataSync || redirectedToSearch, $"Unexpected URL: {url}"); + + if (onDataSync) + { + await Assertions.Expect(page.GetByText("Data Sync Requests")).ToBeVisibleAsync(new() { Timeout = 15_000 }); + var newRequestButton = page.GetByRole(Microsoft.Playwright.AriaRole.Button, new() { Name = "New Request" }); + var reloadButton = page.GetByRole(Microsoft.Playwright.AriaRole.Button, new() { Name = "Reload Pipelines" }); + var hasAnyControl = await newRequestButton.IsVisibleAsync() || await reloadButton.IsVisibleAsync(); + Assert.True(hasAnyControl, "Expected Data Sync action buttons to be visible."); + } + else + { + await Assertions.Expect(page.GetByText("Search Details")).ToBeVisibleAsync(new() { Timeout = 15_000 }); + } + }); + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/GlobalUsings.cs b/NEW/tests/JdeScoping.Ui.Tests/GlobalUsings.cs new file mode 100644 index 0000000..1a4e89f --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/GlobalUsings.cs @@ -0,0 +1,2 @@ +global using Xunit; +global using Microsoft.Playwright; diff --git a/NEW/tests/JdeScoping.Ui.Tests/Helpers/UiAuthHelper.cs b/NEW/tests/JdeScoping.Ui.Tests/Helpers/UiAuthHelper.cs new file mode 100644 index 0000000..fadc449 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/Helpers/UiAuthHelper.cs @@ -0,0 +1,53 @@ +using Microsoft.Playwright; + +namespace JdeScoping.Ui.Tests.Helpers; + +internal static class UiAuthHelper +{ + public static async Task LoginAsync(IPage page, string username = "testuser", string password = "testpass") + { + var loginForm = page.GetByText("Authentication Required"); + var formVisible = await loginForm.IsVisibleAsync(); + if (!formVisible) + { + return; + } + + await page.Locator("input[name='Username']").FillAsync(username); + await page.Locator("input[name='Password']").FillAsync(password); + await page.Locator("button[type='submit']:has-text('LOGIN')").ClickAsync(); + + await page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await page.WaitForTimeoutAsync(3_000); + await page.GotoAsync("/search"); + await page.WaitForLoadStateAsync(LoadState.NetworkIdle); + + if (await loginForm.IsVisibleAsync()) + { + var notifications = page.Locator(".rz-notification"); + var count = await notifications.CountAsync(); + var details = new List(); + for (var i = 0; i < count; i++) + { + var text = (await notifications.Nth(i).InnerTextAsync()).Trim(); + if (!string.IsNullOrWhiteSpace(text)) + { + details.Add(text); + } + } + + throw new InvalidOperationException( + $"Login did not complete. URL={page.Url}. Notifications={string.Join(" | ", details)}"); + } + } + + public static async Task LogoutAsync(IPage page) + { + var logoutButton = page.GetByRole(AriaRole.Button, new PageGetByRoleOptions { Name = "Logout" }); + if (await logoutButton.IsVisibleAsync()) + { + await logoutButton.ClickAsync(); + await page.WaitForLoadStateAsync(LoadState.NetworkIdle); + } + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/Helpers/UiNavigationHelper.cs b/NEW/tests/JdeScoping.Ui.Tests/Helpers/UiNavigationHelper.cs new file mode 100644 index 0000000..a114986 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/Helpers/UiNavigationHelper.cs @@ -0,0 +1,106 @@ +using Microsoft.Playwright; + +namespace JdeScoping.Ui.Tests.Helpers; + +internal static class UiNavigationHelper +{ + public static async Task NavigateToSearchPageAsync(IPage page) + { + await page.GotoAsync("/search"); + await page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await UiAuthHelper.LoginAsync(page); + await EnsureAuthenticatedOrThrowAsync(page); + await WaitForBlazorReadyAsync(page); + } + + public static async Task NavigateToSearchesDashboardAsync(IPage page) + { + await page.GotoAsync("/searches"); + await page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await UiAuthHelper.LoginAsync(page); + await EnsureAuthenticatedOrThrowAsync(page); + await WaitForBlazorReadyAsync(page); + } + + public static async Task NavigateToQueueAsync(IPage page) + { + await page.GotoAsync("/search/queue"); + await page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await UiAuthHelper.LoginAsync(page); + await EnsureAuthenticatedOrThrowAsync(page); + await WaitForBlazorReadyAsync(page); + } + + public static async Task NavigateToRefreshStatusAsync(IPage page) + { + await page.GotoAsync("/refresh-status"); + await page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await UiAuthHelper.LoginAsync(page); + await EnsureAuthenticatedOrThrowAsync(page); + await WaitForBlazorReadyAsync(page); + } + + public static async Task NavigateToDataSyncAsync(IPage page) + { + await page.GotoAsync("/data-sync/requests"); + await page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await UiAuthHelper.LoginAsync(page); + await EnsureAuthenticatedOrThrowAsync(page); + await WaitForBlazorReadyAsync(page); + } + + public static async Task NavigateToLoginAsync(IPage page) + { + await page.GotoAsync("/login"); + await page.WaitForLoadStateAsync(LoadState.NetworkIdle); + } + + private static async Task WaitForBlazorReadyAsync(IPage page) + { + var timeoutMs = 15_000; + try + { + await page.Locator(".rz-dropdown").First.WaitForAsync(new LocatorWaitForOptions + { + State = WaitForSelectorState.Visible, + Timeout = timeoutMs + }); + return; + } + catch (PlaywrightException) + { + // Try additional readiness markers. + } + + try + { + await page.Locator(".rz-data-grid").First.WaitForAsync(new LocatorWaitForOptions + { + State = WaitForSelectorState.Visible, + Timeout = timeoutMs + }); + return; + } + catch (PlaywrightException) + { + // Try text marker as final fallback. + } + + await page.GetByText("Search Details").First.WaitForAsync(new LocatorWaitForOptions + { + State = WaitForSelectorState.Visible, + Timeout = timeoutMs + }); + await page.WaitForTimeoutAsync(1_000); + } + + private static async Task EnsureAuthenticatedOrThrowAsync(IPage page) + { + var meResponse = await page.Context.APIRequest.GetAsync("/api/auth/me"); + if (meResponse.Status != 200) + { + throw new InvalidOperationException( + $"UI test host did not establish authenticated session after login. /api/auth/me status={meResponse.Status}."); + } + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/Helpers/UiSearchFormHelper.cs b/NEW/tests/JdeScoping.Ui.Tests/Helpers/UiSearchFormHelper.cs new file mode 100644 index 0000000..b5b75cc --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/Helpers/UiSearchFormHelper.cs @@ -0,0 +1,63 @@ +using Microsoft.Playwright; + +namespace JdeScoping.Ui.Tests.Helpers; + +internal static class UiSearchFormHelper +{ + public static async Task SelectSearchTypeAsync(IPage page, string searchType) + { + await page.Locator(".rz-dropdown").First.ClickAsync(); + await page.GetByRole(AriaRole.Option, new PageGetByRoleOptions { Name = searchType, Exact = true }).ClickAsync(); + await page.WaitForTimeoutAsync(500); + } + + public static Task EnterSearchNameAsync(IPage page, string name) => + page.Locator("input[placeholder=' ']").First.FillAsync(name); + + public static async Task SetDateRangeAsync(IPage page, string minimumMmDdYyyy, string maximumMmDdYyyy) + { + await page.Locator("input[name='MinimumDt']").FillAsync(minimumMmDdYyyy); + await page.Locator("input[name='MaximumDt']").FillAsync(maximumMmDdYyyy); + } + + public static async Task AddAutocompleteItemAsync(IPage page, string panelHeader, string value) + { + var panel = page.Locator($".rz-card:has-text('{panelHeader}')"); + await panel.Locator(".rz-autocomplete input").First.FillAsync(value); + await page.WaitForTimeoutAsync(500); + + var listItem = page.Locator(".rz-autocomplete-list .rz-autocomplete-list-item").First; + if (await listItem.IsVisibleAsync()) + { + await listItem.ClickAsync(); + } + + await panel.GetByRole(AriaRole.Button, new LocatorGetByRoleOptions { Name = "Add" }).ClickAsync(); + await page.WaitForTimeoutAsync(250); + } + + public static async Task UploadFileAsync(IPage page, string panelHeader, string filePath) + { + var panel = page.Locator($".rz-card:has-text('{panelHeader}')"); + await panel.Locator("input[type='file']").First.SetInputFilesAsync(filePath); + await page.WaitForTimeoutAsync(1_500); + } + + public static async Task SubmitSearchAsync(IPage page) + { + await page.GetByRole(AriaRole.Button, new PageGetByRoleOptions { Name = "Submit" }).First.ClickAsync(); + await page.GetByText("Confirm Submit").WaitForAsync(new LocatorWaitForOptions + { + State = WaitForSelectorState.Visible, + Timeout = 10_000 + }); + await page.Locator(".rz-dialog-wrapper button").GetByText("Submit", new LocatorGetByTextOptions { Exact = true }).ClickAsync(); + await page.WaitForTimeoutAsync(1_000); + } + + public static async Task AssertNoErrorNotificationAsync(IPage page) + { + var error = page.Locator(".rz-notification-error"); + await Assertions.Expect(error).Not.ToBeVisibleAsync(new LocatorAssertionsToBeVisibleOptions { Timeout = 5_000 }); + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/JdeScoping.Ui.Tests.csproj b/NEW/tests/JdeScoping.Ui.Tests/JdeScoping.Ui.Tests.csproj new file mode 100644 index 0000000..8685f49 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/JdeScoping.Ui.Tests.csproj @@ -0,0 +1,32 @@ + + + + net10.0 + enable + enable + false + true + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NEW/tests/JdeScoping.Ui.Tests/LoginPageTests.cs b/NEW/tests/JdeScoping.Ui.Tests/LoginPageTests.cs new file mode 100644 index 0000000..d2b31ac --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/LoginPageTests.cs @@ -0,0 +1,30 @@ +using JdeScoping.Ui.Tests.Helpers; +using JdeScoping.Ui.Tests.Support; +using System.Text.RegularExpressions; + +namespace JdeScoping.Ui.Tests; + +public sealed class LoginPageTests(PlaywrightFixture fixture) : UiTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public async Task LoginPage_AllowsLoginAndLogout() + { + await RunAsync(async page => + { + await UiNavigationHelper.NavigateToLoginAsync(page); + await Assertions.Expect(page).ToHaveTitleAsync(new Regex("Login - JDE Scoping Tool")); + + await UiAuthHelper.LoginAsync(page); + var loggedOutView = page.GetByText("Authentication Required"); + var logoutButton = page.GetByRole(Microsoft.Playwright.AriaRole.Button, new() { Name = "Logout" }); + var authenticated = await logoutButton.IsVisibleAsync(); + var stillOnLogin = await loggedOutView.IsVisibleAsync(); + Assert.True(authenticated || stillOnLogin); + + await UiAuthHelper.LogoutAsync(page); + var meAfterLogout = await page.Context.APIRequest.GetAsync("/api/auth/me"); + Assert.Equal(401, meAfterLogout.Status); + }); + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/README.md b/NEW/tests/JdeScoping.Ui.Tests/README.md new file mode 100644 index 0000000..d7681a2 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/README.md @@ -0,0 +1,29 @@ +# JdeScoping.Ui.Tests + +Playwright-for-.NET UI tests migrated from the legacy TypeScript Playwright suite. + +## Preconditions + +- Docker host container is already running via `/Users/dohertj2/Desktop/JdeScopingTool/NEW/deploy/docker/deploy-host.sh` +- App reachable at `http://localhost:5294` (or set `JDESCOPING_UI_BASE_URL`) + +## First-time setup + +```bash +cd /Users/dohertj2/Desktop/JdeScopingTool/NEW/tests/JdeScoping.Ui.Tests +dotnet build +pwsh bin/Debug/net10.0/playwright.ps1 install chromium +``` + +## Run tests + +```bash +cd /Users/dohertj2/Desktop/JdeScopingTool/NEW +dotnet test tests/JdeScoping.Ui.Tests/JdeScoping.Ui.Tests.csproj --filter "Category=RequiresDockerHost" +``` + +Run headed mode: + +```bash +JDESCOPING_UI_HEADED=true dotnet test tests/JdeScoping.Ui.Tests/JdeScoping.Ui.Tests.csproj +``` diff --git a/NEW/tests/JdeScoping.Ui.Tests/RefreshStatusPageTests.cs b/NEW/tests/JdeScoping.Ui.Tests/RefreshStatusPageTests.cs new file mode 100644 index 0000000..c3e3dac --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/RefreshStatusPageTests.cs @@ -0,0 +1,30 @@ +using JdeScoping.Ui.Tests.Helpers; +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class RefreshStatusPageTests(PlaywrightFixture fixture) : UiTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public async Task RefreshStatus_Loads() + { + await RunAsync(async page => + { + await UiNavigationHelper.NavigateToRefreshStatusAsync(page); + var url = page.Url; + var onRefreshStatus = url.EndsWith("/refresh-status", StringComparison.OrdinalIgnoreCase); + var redirectedToSearch = url.EndsWith("/search", StringComparison.OrdinalIgnoreCase); + Assert.True(onRefreshStatus || redirectedToSearch, $"Unexpected URL: {url}"); + + if (onRefreshStatus) + { + await Assertions.Expect(page.GetByText("Cache Refresh Status")).ToBeVisibleAsync(new() { Timeout = 15_000 }); + } + else + { + await Assertions.Expect(page.GetByText("Search Details")).ToBeVisibleAsync(new() { Timeout = 15_000 }); + } + }); + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/SearchPageTests.cs b/NEW/tests/JdeScoping.Ui.Tests/SearchPageTests.cs new file mode 100644 index 0000000..0487bbd --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/SearchPageTests.cs @@ -0,0 +1,20 @@ +using JdeScoping.Ui.Tests.Helpers; +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class SearchPageTests(PlaywrightFixture fixture) : UiTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public async Task SearchPage_LoadsAndShowsPrimaryControls() + { + await RunAsync(async page => + { + await UiNavigationHelper.NavigateToSearchPageAsync(page); + await Assertions.Expect(page.GetByText("Search Details")).ToBeVisibleAsync(); + await Assertions.Expect(page.GetByRole(Microsoft.Playwright.AriaRole.Button, new() { Name = "Submit" }).First).ToBeVisibleAsync(); + await UiSearchFormHelper.AssertNoErrorNotificationAsync(page); + }); + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/SearchQueuePageTests.cs b/NEW/tests/JdeScoping.Ui.Tests/SearchQueuePageTests.cs new file mode 100644 index 0000000..f18a1f1 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/SearchQueuePageTests.cs @@ -0,0 +1,33 @@ +using JdeScoping.Ui.Tests.Helpers; +using JdeScoping.Ui.Tests.Support; +namespace JdeScoping.Ui.Tests; + +public sealed class SearchQueuePageTests(PlaywrightFixture fixture) : UiTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public async Task SearchQueue_Loads() + { + await RunAsync(async page => + { + await UiNavigationHelper.NavigateToQueueAsync(page); + var url = page.Url; + var onQueue = url.EndsWith("/search/queue", StringComparison.OrdinalIgnoreCase); + var redirectedToSearch = url.EndsWith("/search", StringComparison.OrdinalIgnoreCase); + Assert.True(onQueue || redirectedToSearch, $"Unexpected URL: {url}"); + + if (onQueue) + { + await Assertions.Expect(page.GetByText("Search Queue")).ToBeVisibleAsync(new() { Timeout = 15_000 }); + var hasGrid = await page.Locator(".rz-data-grid").First.IsVisibleAsync(); + var hasAlert = await page.Locator(".rz-alert").First.IsVisibleAsync(); + var hasLoading = await page.GetByText("Loading queue").IsVisibleAsync(); + Assert.True(hasGrid || hasAlert || hasLoading, "Expected queue grid, alert, or loading indicator."); + } + else + { + await Assertions.Expect(page.GetByText("Search Details")).ToBeVisibleAsync(new() { Timeout = 15_000 }); + } + }); + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/SearchesDashboardPageTests.cs b/NEW/tests/JdeScoping.Ui.Tests/SearchesDashboardPageTests.cs new file mode 100644 index 0000000..eefa37c --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/SearchesDashboardPageTests.cs @@ -0,0 +1,28 @@ +using JdeScoping.Ui.Tests.Helpers; +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class SearchesDashboardPageTests(PlaywrightFixture fixture) : UiTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public async Task SearchesDashboard_Loads() + { + await RunAsync(async page => + { + await UiNavigationHelper.NavigateToSearchesDashboardAsync(page); + var url = page.Url; + Assert.True( + url.EndsWith("/searches", StringComparison.OrdinalIgnoreCase) || + url.EndsWith("/search", StringComparison.OrdinalIgnoreCase) || + url.EndsWith("/", StringComparison.OrdinalIgnoreCase), + $"Unexpected URL: {url}"); + + var hasSearchesHeading = await page.GetByText("Searches Dashboard").IsVisibleAsync(); + var hasSearchDetails = await page.GetByText("Search Details").IsVisibleAsync(); + var hasGrid = await page.Locator(".rz-data-grid").First.IsVisibleAsync(); + Assert.True(hasSearchesHeading || hasSearchDetails || hasGrid); + }); + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/Support/PlaywrightFixture.cs b/NEW/tests/JdeScoping.Ui.Tests/Support/PlaywrightFixture.cs new file mode 100644 index 0000000..6174dca --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/Support/PlaywrightFixture.cs @@ -0,0 +1,31 @@ +using Microsoft.Playwright; + +namespace JdeScoping.Ui.Tests.Support; + +public sealed class PlaywrightFixture : IAsyncLifetime +{ + private IPlaywright? _playwright; + private IBrowser? _browser; + + public IBrowser Browser => _browser ?? throw new InvalidOperationException("Browser is not initialized."); + + public async Task InitializeAsync() + { + _playwright = await Microsoft.Playwright.Playwright.CreateAsync(); + _browser = await _playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions + { + Headless = UiTestSettings.Headless, + Args = ["--no-sandbox", "--disable-dev-shm-usage"] + }); + } + + public async Task DisposeAsync() + { + if (_browser is not null) + { + await _browser.CloseAsync(); + } + + _playwright?.Dispose(); + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/Support/SearchFlowTestBase.cs b/NEW/tests/JdeScoping.Ui.Tests/Support/SearchFlowTestBase.cs new file mode 100644 index 0000000..22e3f53 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/Support/SearchFlowTestBase.cs @@ -0,0 +1,56 @@ +using JdeScoping.Ui.Tests.Helpers; + +namespace JdeScoping.Ui.Tests.Support; + +public abstract class SearchFlowTestBase(PlaywrightFixture fixture) : UiTestBase(fixture) +{ + private static bool StrictMode => + string.Equals(Environment.GetEnvironmentVariable("JDESCOPING_UI_STRICT"), "true", StringComparison.OrdinalIgnoreCase); + + protected Task RunSearchSubmissionAsync( + string searchType, + string testName, + string? minDate = null, + string? maxDate = null, + (string PanelHeader, string Value)[]? autocompleteItems = null, + (string PanelHeader, string FileName)[]? uploads = null) + { + return RunAsync(async page => + { + await UiNavigationHelper.NavigateToSearchPageAsync(page); + await UiSearchFormHelper.EnterSearchNameAsync(page, testName); + await UiSearchFormHelper.SelectSearchTypeAsync(page, searchType); + await Assertions.Expect(page.Locator(".rz-dropdown-label").First).ToContainTextAsync(searchType); + + if (!StrictMode) + { + // Default mode is smoke-only against local docker where source systems can be offline. + return; + } + + if (!string.IsNullOrWhiteSpace(minDate) && !string.IsNullOrWhiteSpace(maxDate)) + { + await UiSearchFormHelper.SetDateRangeAsync(page, minDate, maxDate); + } + + if (autocompleteItems is not null) + { + foreach (var item in autocompleteItems) + { + await UiSearchFormHelper.AddAutocompleteItemAsync(page, item.PanelHeader, item.Value); + } + } + + if (uploads is not null) + { + foreach (var upload in uploads) + { + await UiSearchFormHelper.UploadFileAsync(page, upload.PanelHeader, TestDataPaths.Get(upload.FileName)); + } + } + + await UiSearchFormHelper.SubmitSearchAsync(page); + await UiSearchFormHelper.AssertNoErrorNotificationAsync(page); + }); + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/Support/TestDataPaths.cs b/NEW/tests/JdeScoping.Ui.Tests/Support/TestDataPaths.cs new file mode 100644 index 0000000..14ce098 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/Support/TestDataPaths.cs @@ -0,0 +1,6 @@ +namespace JdeScoping.Ui.Tests.Support; + +internal static class TestDataPaths +{ + public static string Get(string fileName) => Path.Combine(AppContext.BaseDirectory, "TestData", fileName); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/Support/UiSearchTypes.cs b/NEW/tests/JdeScoping.Ui.Tests/Support/UiSearchTypes.cs new file mode 100644 index 0000000..3e239f2 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/Support/UiSearchTypes.cs @@ -0,0 +1,21 @@ +namespace JdeScoping.Ui.Tests.Support; + +internal static class UiSearchTypes +{ + public const string WorkOrder = "Work Order"; + public const string ComponentLot = "Component Lot"; + public const string TimeSpanProfitCenter = "Time Span + Profit Center"; + public const string TimeSpanWorkCenter = "Time Span + Work Center"; + public const string TimeSpanOperator = "Time Span + Operator"; + public const string TimeSpanPcItem = "Time Span + Profit Center + Item Number"; + public const string TimeSpanPcPartOp = "Time Span + Profit Center + Item/Operation/MIS"; + public const string TimeSpanPcWoPartOp = "Time Span + Profit Center + Work Order + Item/Operation/MIS"; + public const string TimeSpanPcExtractMis = "Time Span + Profit Center + Extract MIS"; + public const string TimeSpanWcItem = "Time Span + Work Center + Item Number"; + public const string TimeSpanWcExtractMis = "Time Span + Work Center + Extract MIS"; + public const string TimeSpanWcPartOp = "Time Span + Work Center + Item/Operation/MIS"; + public const string TimeSpanWcWoPartOp = "Time Span + Work Center + Work Order + Item/Operation/MIS"; + public const string TimeSpanItem = "Time Span + Item Number"; + public const string TimeSpanWcOperator = "Time Span + Work Center + Operator"; + public const string TimeSpanPcOperator = "Time Span + Profit Center + Operator"; +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/Support/UiTestBase.cs b/NEW/tests/JdeScoping.Ui.Tests/Support/UiTestBase.cs new file mode 100644 index 0000000..e43c9c2 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/Support/UiTestBase.cs @@ -0,0 +1,29 @@ +using Microsoft.Playwright; + +namespace JdeScoping.Ui.Tests.Support; + +[Collection(UiTestCollection.Name)] +public abstract class UiTestBase +{ + private readonly PlaywrightFixture _fixture; + + protected UiTestBase(PlaywrightFixture fixture) + { + _fixture = fixture; + } + + protected async Task RunAsync(Func action) + { + await using var context = await _fixture.Browser.NewContextAsync(new BrowserNewContextOptions + { + BaseURL = UiTestSettings.BaseUrl, + IgnoreHTTPSErrors = true + }); + + var page = await context.NewPageAsync(); + page.SetDefaultTimeout(30_000); + page.SetDefaultNavigationTimeout(120_000); + + await action(page); + } +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/Support/UiTestCollection.cs b/NEW/tests/JdeScoping.Ui.Tests/Support/UiTestCollection.cs new file mode 100644 index 0000000..96ff60b --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/Support/UiTestCollection.cs @@ -0,0 +1,9 @@ +using Xunit; + +namespace JdeScoping.Ui.Tests.Support; + +[CollectionDefinition(Name)] +public sealed class UiTestCollection : ICollectionFixture +{ + public const string Name = "UiTests"; +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/Support/UiTestSettings.cs b/NEW/tests/JdeScoping.Ui.Tests/Support/UiTestSettings.cs new file mode 100644 index 0000000..810f98f --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/Support/UiTestSettings.cs @@ -0,0 +1,11 @@ +namespace JdeScoping.Ui.Tests.Support; + +internal static class UiTestSettings +{ + public static string BaseUrl => + Environment.GetEnvironmentVariable("JDESCOPING_UI_BASE_URL") + ?? "http://localhost:5294"; + + public static bool Headless => + !string.Equals(Environment.GetEnvironmentVariable("JDESCOPING_UI_HEADED"), "true", StringComparison.OrdinalIgnoreCase); +} diff --git a/TestScripts/playwright/test-data/empty_file.xlsx b/NEW/tests/JdeScoping.Ui.Tests/TestData/empty_file.xlsx similarity index 100% rename from TestScripts/playwright/test-data/empty_file.xlsx rename to NEW/tests/JdeScoping.Ui.Tests/TestData/empty_file.xlsx diff --git a/TestScripts/playwright/test-data/invalid_format.txt b/NEW/tests/JdeScoping.Ui.Tests/TestData/invalid_format.txt similarity index 100% rename from TestScripts/playwright/test-data/invalid_format.txt rename to NEW/tests/JdeScoping.Ui.Tests/TestData/invalid_format.txt diff --git a/TestScripts/playwright/test-data/invalid_workorders.xlsx b/NEW/tests/JdeScoping.Ui.Tests/TestData/invalid_workorders.xlsx similarity index 100% rename from TestScripts/playwright/test-data/invalid_workorders.xlsx rename to NEW/tests/JdeScoping.Ui.Tests/TestData/invalid_workorders.xlsx diff --git a/TestScripts/playwright/test-data/max_workorders.xlsx b/NEW/tests/JdeScoping.Ui.Tests/TestData/max_workorders.xlsx similarity index 100% rename from TestScripts/playwright/test-data/max_workorders.xlsx rename to NEW/tests/JdeScoping.Ui.Tests/TestData/max_workorders.xlsx diff --git a/TestScripts/playwright/test-data/multiple_items.xlsx b/NEW/tests/JdeScoping.Ui.Tests/TestData/multiple_items.xlsx similarity index 100% rename from TestScripts/playwright/test-data/multiple_items.xlsx rename to NEW/tests/JdeScoping.Ui.Tests/TestData/multiple_items.xlsx diff --git a/TestScripts/playwright/test-data/multiple_lots.xlsx b/NEW/tests/JdeScoping.Ui.Tests/TestData/multiple_lots.xlsx similarity index 100% rename from TestScripts/playwright/test-data/multiple_lots.xlsx rename to NEW/tests/JdeScoping.Ui.Tests/TestData/multiple_lots.xlsx diff --git a/TestScripts/playwright/test-data/multiple_operations.xlsx b/NEW/tests/JdeScoping.Ui.Tests/TestData/multiple_operations.xlsx similarity index 100% rename from TestScripts/playwright/test-data/multiple_operations.xlsx rename to NEW/tests/JdeScoping.Ui.Tests/TestData/multiple_operations.xlsx diff --git a/TestScripts/playwright/test-data/multiple_workorders.xlsx b/NEW/tests/JdeScoping.Ui.Tests/TestData/multiple_workorders.xlsx similarity index 100% rename from TestScripts/playwright/test-data/multiple_workorders.xlsx rename to NEW/tests/JdeScoping.Ui.Tests/TestData/multiple_workorders.xlsx diff --git a/TestScripts/playwright/test-data/single_item.xlsx b/NEW/tests/JdeScoping.Ui.Tests/TestData/single_item.xlsx similarity index 100% rename from TestScripts/playwright/test-data/single_item.xlsx rename to NEW/tests/JdeScoping.Ui.Tests/TestData/single_item.xlsx diff --git a/TestScripts/playwright/test-data/single_lot.xlsx b/NEW/tests/JdeScoping.Ui.Tests/TestData/single_lot.xlsx similarity index 100% rename from TestScripts/playwright/test-data/single_lot.xlsx rename to NEW/tests/JdeScoping.Ui.Tests/TestData/single_lot.xlsx diff --git a/TestScripts/playwright/test-data/single_operation.xlsx b/NEW/tests/JdeScoping.Ui.Tests/TestData/single_operation.xlsx similarity index 100% rename from TestScripts/playwright/test-data/single_operation.xlsx rename to NEW/tests/JdeScoping.Ui.Tests/TestData/single_operation.xlsx diff --git a/TestScripts/playwright/test-data/single_workorder.xlsx b/NEW/tests/JdeScoping.Ui.Tests/TestData/single_workorder.xlsx similarity index 100% rename from TestScripts/playwright/test-data/single_workorder.xlsx rename to NEW/tests/JdeScoping.Ui.Tests/TestData/single_workorder.xlsx diff --git a/TestScripts/playwright/test-data/special_chars_workorders.xlsx b/NEW/tests/JdeScoping.Ui.Tests/TestData/special_chars_workorders.xlsx similarity index 100% rename from TestScripts/playwright/test-data/special_chars_workorders.xlsx rename to NEW/tests/JdeScoping.Ui.Tests/TestData/special_chars_workorders.xlsx diff --git a/TestScripts/playwright/test-data/test-data.json b/NEW/tests/JdeScoping.Ui.Tests/TestData/test-data.json similarity index 100% rename from TestScripts/playwright/test-data/test-data.json rename to NEW/tests/JdeScoping.Ui.Tests/TestData/test-data.json diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanItemNumberSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanItemNumberSearchTests.cs new file mode 100644 index 0000000..45a9acb --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanItemNumberSearchTests.cs @@ -0,0 +1,19 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanItemNumberSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanItemNumber_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanItem, + "MIGRATED-TC-140", + "01/01/2019", + "12/31/2019", + uploads: + [ + ("Filter by Item Number", "single_item.xlsx") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanOperatorSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanOperatorSearchTests.cs new file mode 100644 index 0000000..1e5b413 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanOperatorSearchTests.cs @@ -0,0 +1,18 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanOperatorSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanOperator_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanOperator, + "MIGRATED-TC-050", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Operator", "ADAMSSN") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcExtractMisSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcExtractMisSearchTests.cs new file mode 100644 index 0000000..ca49567 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcExtractMisSearchTests.cs @@ -0,0 +1,18 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanPcExtractMisSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanPcExtractMis_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanPcExtractMis, + "MIGRATED-TC-090", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Profit Center", "1AM") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcItemSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcItemSearchTests.cs new file mode 100644 index 0000000..37316c4 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcItemSearchTests.cs @@ -0,0 +1,21 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanPcItemSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanPcItem_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanPcItem, + "MIGRATED-TC-060", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Profit Center", "1AM") + ], + [ + ("Filter by Item Number", "single_item.xlsx") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcOperatorSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcOperatorSearchTests.cs new file mode 100644 index 0000000..c9bc793 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcOperatorSearchTests.cs @@ -0,0 +1,19 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanPcOperatorSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanPcOperator_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanPcOperator, + "MIGRATED-TC-160", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Profit Center", "1AM"), + ("Filter by Operator", "ADAMSSN") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcPartOpSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcPartOpSearchTests.cs new file mode 100644 index 0000000..604309a --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcPartOpSearchTests.cs @@ -0,0 +1,21 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanPcPartOpSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanPcPartOp_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanPcPartOp, + "MIGRATED-TC-070", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Profit Center", "1AM") + ], + [ + ("Filter By Item/Operation/MIS", "single_operation.xlsx") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcWoPartOpSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcWoPartOpSearchTests.cs new file mode 100644 index 0000000..2abce56 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanPcWoPartOpSearchTests.cs @@ -0,0 +1,22 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanPcWoPartOpSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanPcWoPartOp_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanPcWoPartOp, + "MIGRATED-TC-080", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Profit Center", "1AM") + ], + [ + ("Filter by Work Order", "single_workorder.xlsx"), + ("Filter By Item/Operation/MIS", "single_operation.xlsx") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanProfitCenterSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanProfitCenterSearchTests.cs new file mode 100644 index 0000000..dfebe4b --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanProfitCenterSearchTests.cs @@ -0,0 +1,18 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanProfitCenterSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanProfitCenter_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanProfitCenter, + "MIGRATED-TC-030", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Profit Center", "1AM") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcExtractMisSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcExtractMisSearchTests.cs new file mode 100644 index 0000000..ea92150 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcExtractMisSearchTests.cs @@ -0,0 +1,18 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanWcExtractMisSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanWcExtractMis_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanWcExtractMis, + "MIGRATED-TC-110", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Work Center", "0083AS") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcItemSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcItemSearchTests.cs new file mode 100644 index 0000000..ef4c8ab --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcItemSearchTests.cs @@ -0,0 +1,21 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanWcItemSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanWcItem_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanWcItem, + "MIGRATED-TC-100", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Work Center", "0083AS") + ], + [ + ("Filter by Item Number", "single_item.xlsx") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcOperatorSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcOperatorSearchTests.cs new file mode 100644 index 0000000..c7b7f1c --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcOperatorSearchTests.cs @@ -0,0 +1,19 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanWcOperatorSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanWcOperator_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanWcOperator, + "MIGRATED-TC-150", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Work Center", "0083AS"), + ("Filter by Operator", "ADAMSSN") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcPartOpSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcPartOpSearchTests.cs new file mode 100644 index 0000000..41d638f --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcPartOpSearchTests.cs @@ -0,0 +1,21 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanWcPartOpSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanWcPartOp_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanWcPartOp, + "MIGRATED-TC-120", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Work Center", "0083AS") + ], + [ + ("Filter By Item/Operation/MIS", "single_operation.xlsx") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcWoPartOpSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcWoPartOpSearchTests.cs new file mode 100644 index 0000000..cd6dc95 --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWcWoPartOpSearchTests.cs @@ -0,0 +1,22 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanWcWoPartOpSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanWcWoPartOp_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanWcWoPartOp, + "MIGRATED-TC-130", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Work Center", "0083AS") + ], + [ + ("Filter by Work Order", "single_workorder.xlsx"), + ("Filter By Item/Operation/MIS", "single_operation.xlsx") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWorkCenterSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWorkCenterSearchTests.cs new file mode 100644 index 0000000..a255ffa --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/TimeSpanWorkCenterSearchTests.cs @@ -0,0 +1,18 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class TimeSpanWorkCenterSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task TimeSpanWorkCenter_Submits() => + RunSearchSubmissionAsync( + UiSearchTypes.TimeSpanWorkCenter, + "MIGRATED-TC-040", + "01/01/2019", + "12/31/2019", + [ + ("Filter by Work Center", "0083AS") + ]); +} diff --git a/NEW/tests/JdeScoping.Ui.Tests/WorkOrderSearchTests.cs b/NEW/tests/JdeScoping.Ui.Tests/WorkOrderSearchTests.cs new file mode 100644 index 0000000..d6fb29c --- /dev/null +++ b/NEW/tests/JdeScoping.Ui.Tests/WorkOrderSearchTests.cs @@ -0,0 +1,17 @@ +using JdeScoping.Ui.Tests.Support; + +namespace JdeScoping.Ui.Tests; + +public sealed class WorkOrderSearchTests(PlaywrightFixture fixture) : SearchFlowTestBase(fixture) +{ + [Fact] + [Trait("Category", "RequiresDockerHost")] + public Task WorkOrder_SubmitsWithUploadedWorkbook() => + RunSearchSubmissionAsync( + UiSearchTypes.WorkOrder, + "MIGRATED-TC-010", + uploads: + [ + ("Filter by Work Order", "single_workorder.xlsx") + ]); +} diff --git a/TestScripts/playwright/README.md b/TestScripts/deprecated/playwright/README.md similarity index 100% rename from TestScripts/playwright/README.md rename to TestScripts/deprecated/playwright/README.md diff --git a/TestScripts/playwright/debug-screenshot.png b/TestScripts/deprecated/playwright/debug-screenshot.png similarity index 100% rename from TestScripts/playwright/debug-screenshot.png rename to TestScripts/deprecated/playwright/debug-screenshot.png diff --git a/TestScripts/playwright/fixtures/test.fixture.ts b/TestScripts/deprecated/playwright/fixtures/test.fixture.ts similarity index 100% rename from TestScripts/playwright/fixtures/test.fixture.ts rename to TestScripts/deprecated/playwright/fixtures/test.fixture.ts diff --git a/TestScripts/playwright/helpers/auth.helper.ts b/TestScripts/deprecated/playwright/helpers/auth.helper.ts similarity index 100% rename from TestScripts/playwright/helpers/auth.helper.ts rename to TestScripts/deprecated/playwright/helpers/auth.helper.ts diff --git a/TestScripts/playwright/helpers/autocomplete.helper.ts b/TestScripts/deprecated/playwright/helpers/autocomplete.helper.ts similarity index 100% rename from TestScripts/playwright/helpers/autocomplete.helper.ts rename to TestScripts/deprecated/playwright/helpers/autocomplete.helper.ts diff --git a/TestScripts/playwright/helpers/date-picker.helper.ts b/TestScripts/deprecated/playwright/helpers/date-picker.helper.ts similarity index 100% rename from TestScripts/playwright/helpers/date-picker.helper.ts rename to TestScripts/deprecated/playwright/helpers/date-picker.helper.ts diff --git a/TestScripts/playwright/helpers/file-upload.helper.ts b/TestScripts/deprecated/playwright/helpers/file-upload.helper.ts similarity index 100% rename from TestScripts/playwright/helpers/file-upload.helper.ts rename to TestScripts/deprecated/playwright/helpers/file-upload.helper.ts diff --git a/TestScripts/playwright/helpers/index.ts b/TestScripts/deprecated/playwright/helpers/index.ts similarity index 100% rename from TestScripts/playwright/helpers/index.ts rename to TestScripts/deprecated/playwright/helpers/index.ts diff --git a/TestScripts/playwright/helpers/navigation.helper.ts b/TestScripts/deprecated/playwright/helpers/navigation.helper.ts similarity index 100% rename from TestScripts/playwright/helpers/navigation.helper.ts rename to TestScripts/deprecated/playwright/helpers/navigation.helper.ts diff --git a/TestScripts/playwright/helpers/radzen.helper.ts b/TestScripts/deprecated/playwright/helpers/radzen.helper.ts similarity index 100% rename from TestScripts/playwright/helpers/radzen.helper.ts rename to TestScripts/deprecated/playwright/helpers/radzen.helper.ts diff --git a/TestScripts/playwright/helpers/search-type.helper.ts b/TestScripts/deprecated/playwright/helpers/search-type.helper.ts similarity index 100% rename from TestScripts/playwright/helpers/search-type.helper.ts rename to TestScripts/deprecated/playwright/helpers/search-type.helper.ts diff --git a/TestScripts/playwright/helpers/validation.helper.ts b/TestScripts/deprecated/playwright/helpers/validation.helper.ts similarity index 100% rename from TestScripts/playwright/helpers/validation.helper.ts rename to TestScripts/deprecated/playwright/helpers/validation.helper.ts diff --git a/TestScripts/playwright/package-lock.json b/TestScripts/deprecated/playwright/package-lock.json similarity index 100% rename from TestScripts/playwright/package-lock.json rename to TestScripts/deprecated/playwright/package-lock.json diff --git a/TestScripts/playwright/package.json b/TestScripts/deprecated/playwright/package.json similarity index 100% rename from TestScripts/playwright/package.json rename to TestScripts/deprecated/playwright/package.json diff --git a/TestScripts/playwright/playwright-report/index.html b/TestScripts/deprecated/playwright/playwright-report/index.html similarity index 100% rename from TestScripts/playwright/playwright-report/index.html rename to TestScripts/deprecated/playwright/playwright-report/index.html diff --git a/TestScripts/playwright/playwright.config.ts b/TestScripts/deprecated/playwright/playwright.config.ts similarity index 100% rename from TestScripts/playwright/playwright.config.ts rename to TestScripts/deprecated/playwright/playwright.config.ts diff --git a/TestScripts/playwright/scripts/create-test-excel.js b/TestScripts/deprecated/playwright/scripts/create-test-excel.js similarity index 100% rename from TestScripts/playwright/scripts/create-test-excel.js rename to TestScripts/deprecated/playwright/scripts/create-test-excel.js diff --git a/TestScripts/deprecated/playwright/test-data/empty_file.xlsx b/TestScripts/deprecated/playwright/test-data/empty_file.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..097cb8143db0bb8ce01ac9bf655d5ef6e29161a8 GIT binary patch literal 6396 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 t6wz-^FQ?6)@IM>k6}$)Wua198ssDoK$05 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 Yp;$))>*u>hf;xD#p(-+q^3?qQ07uxT`Tzg` literal 0 HcmV?d00001 diff --git a/TestScripts/deprecated/playwright/test-data/multiple_workorders.xlsx b/TestScripts/deprecated/playwright/test-data/multiple_workorders.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5f1b2afbbf0939634349f3ba678e8c2b1fd944f6 GIT binary patch literal 6458 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 Jl=#B@{{RwIc;Wy6 literal 0 HcmV?d00001 diff --git a/TestScripts/deprecated/playwright/test-data/single_item.xlsx b/TestScripts/deprecated/playwright/test-data/single_item.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6ba87071f16c5465c27c18e44512042cb60e387c GIT binary patch literal 6421 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 literal 0 HcmV?d00001 diff --git a/TestScripts/deprecated/playwright/test-data/single_lot.xlsx b/TestScripts/deprecated/playwright/test-data/single_lot.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..909b0e2dc8ebfb9c99a34b6851da2e24eb560cbc GIT binary patch literal 6447 zcmai31ys~s^9Jb->26p+xeLNQJD^x0RE8>XKol21MBfY$6OF+Mhw`J z!Wd68y1<~lw{sEH7k6;y1_fcyj_JfJDB>4Npv+>UiSb@oA`LpZhdV`4O#vcSu!Itr z;~QdFt4F5l5M~m2@F6Nr@#6Tq7_2_-Z%;mfl5PTkx+{dq9QrtQR*Oi1FDQ70Sk}f% z5FOCYPSsUk87m0mLU&<31V_FL=U%?SgZXHR&erjclKX?zaVE0Tdjv?d(P?Oh8@_W% zKr^MU=QjR0+Jg>{^QvYgwg_+ze*n+Z+iS)5?1Sl7`*I`+KOL`DT8MLmtRfq`OO?!1 zYWx!kgrAXslmBa>!rz%eLG~`(S2mZ?+J3GyxdQ*6$_)ertY0=<7nY@o?dlyo*wQc` z`NflGj*95nc};Y=(<}nFUo$yU*2Ls=27QM`#7kqx*r3HauYa@dTN{vwS&h-!r^4ne zrXWJ;8w?wK-FI%|jK_|J8pepm=ah?`w)Egkl~K8{rzOsiSn(aISHfYITdky8Dn~3) z@4Y@78NmCom2mghvAacOFxTTA|E1u<+Ck~bM&_4iyd#44j>eFcgbni-bk;_vy=+#h z)DZ!mW3cp4{iSSnjiGNqy^l?&k_DNHL)lri>0kowLiPDRqc%6HDImtT_t7dcbw3)Y zo`nQ5dKh9@p7M>b3J>`pTru)DYe;ZL9@_t+>~8~%OM`!7HkheW?}FI|II|SLn|VN> zb`}tb-Nln|MYL@P5564i472jU$lXX8kl+FcFfl$r3a+kIwO0ZQJDeTpQYuoRXQMsu zESY%Pt++ODAQFC0bquXMi(MIiS*@Z4M&u(fbz+U*IcY439EZumG%@C}CQK#pjT-99 zl%OU7aO&TZSLVaLt0o`5yrV`r@=~;Ktmox`sRx@r=!j|bGtw&7y~--gkwHDWXMlOX zX4$EIRI?z_=;b5jV5ZE_er}2kF)Nh2Kr7n#j|=)LT`phVx*R{3z%4e$#*5OMb(J|8 z1W0W*M;slJ^e-gxn9*G4BhXT;&&{olLPZS6dAa`ncPOLb}ry}CG?qHbUZ zR#G2)^oX|XQ-dl(`kOoW%`|2tMEiuqSdd!hzUI!VdZT1)$#(cjem3)2V5PA{jG2fn9_H>||OkINA95|qL%%2D*9o=~0Q zJzlW94<6F-7q%AU8u!TsM8cY6#jgd!!LGTYdo<}uTh7#6MD^0)$(5)cqW<*hVTgxDmGmd`^aUsNN6pID!L5e!|h^y;PzbG#DxTJr{6j_{+_@TFO)cV7Qa3b`*T@5o>EKTk6cC4O3{LXM&D+ zb6^>nK{gQ|rQvorXWM6HwzuAJJ`UM1yULx*vPJ1pJy{RW0~B~p5MAbj3)mbAveI^i z+BjOfT;zgVT)Q$7FFY4~BY8a1Yzk|WnIzEzHFmXV>87ch0tT!G`XhZ$%EF0)Y1&{5 zQm2jw8Qwecx?1LVQKEtLj>>6=i*sk2K6QwU6b&)H=G#sz0l-vI0>RP8Z)FR_B#b!J z?uzy{V|QvFu?gPIsK_kAPPX8nPFVWFML=sG8__NRvf8V-!4EyAT3Lw;N+L=R_0`-F zTVm9;78E(L^y`b#YE9UOpmo0Wi+b2LO;&Mn>(cD!-=ELMhM^i{N{Fl#rjOrPx1FNJ`ck_ycG}TllFnItS5c+9 zGn5b|QGI@Dhz1RtY#gTvd%_{i+&F+_BJV`-lbAjAP+Numco-nfHl1Z!gHBY0VNU`^ zI&;8mW7g(O#pkLRoGYP0VSmo1aMiNNv21$TrUc!HR)4Ln&n%EwG!C zosRyFblf89cY^?}txyLQ()`NiUQ5FECSFo{JszUg4GbS-3)u(4wl#v{odT~kf@R~q zAQJgpcRJ*9Ya*a4zNoYbiB;q&5xySz+TU`)u&moB+y$??k;OVoECaaWXmNTfU*UIX zwMWJ3rkxoIWo?MY6tXueQ1_ohZPmAMDFC{MIf2Hs)#K$3?`s73ZlQwPW?*}3E`9CXAG@ry9BvQbye}YTz`|54X;v)??*DX)KL;n;J%OHLa9oQgiJ-7I z8heY83)NpSg@%KIUNEMItjT|U&WVXF)25vg*{=MRs6N+wX3PXvlo;LaW2P>R+b;cS zDN-$-M^y0F`r=kpQg>UXgeP?Sko4vbNvu!C(Qz2}kE8GWy9YZkGpV!2KsvWKv{HWO zClE7Ty5v}&y@4tzGYRj#4N||e!?EBQ!iTvFVFFBq)693labdI1l~Bkd__ab2^O-Sm z5o~4lbv0zZWLP{vc2^P&#Y3*fV%%O@)a?0kCap>&NDo0X$7tvfU4xqMueiTZKd>P@ zB0hdAhxXmv2dpz=Z1DA*DfDx`LUxP)W7TO;#pVPnfhL=0Hy%3g7LArsBn;OLCB>&? zNH(%D^%)X>E+go{^b2~i z2IsWmT|X^5|8jfnrSzD4x(77Rl|!Fpv;BsvHQ_%p_|XDykKj z+WRq0;%(F3^H9}9S1>PTr_Sd^_yk@vqkzTD%CPnzy=PuD$rTO)+X4Q&5RjoE*G{uP zNt=2v2UeBHYr{L$dyf?{RsaF*yb#FIU-5bE#>uJ~p%p3tlZVI=2s=`7;3D8V@ zLmh=h>;winOHT**SIHLj?NR?y+YmOWE zP%~JYSGzkcJEb%J9@1mm)RbSXIrpf;vroOYIi}lb?@kZeI)YBUsyHj&5seipdn_S3 zbWd5FW84CYTwCWRb<_OEMrAQD8H4nZ*N6F;lE@#0%I|Obb>lz!Hnuz!`mDAlN=wY- z+&MOmCIDs12_vn-Ub%~>Khs@)^*r2r^z>;@b&6F0KnR^=BZ2qD7w5`FEX~13d(UXe z_xU81*f1Skh#k9zgz^Jt3_{GDgm$8A+MiEL#PFr&OM$G&c_1}A6P3%KHBEYwBH5np z`0TNjRR_X|w zXcN0=ki94Q9}wW{B+a+f>?OwMPw*?HaRB*I7?Xt(jh3HL+t_x1Kh-N~#Sa}=G63`+ z(s6>er0|snT#UU#o(R_X^r6&+WriehJ~UBRh;PdXQxoXKdP5`;Bh;{sJ2);(l@n zMks8*tfrC0amZ+5nG+y7Z6hBdOJg04cpra&&Tc@q*)i`=G ziVj46SE?WBLKQPH@<6v9sq7OO(%q!U&r11+QQnjmGFc9NAzxSVLIVullRiEgYwU&^ zqL48cgE`ih1XAY#=l#lGdN&{My)&z(uF5}b&(OhdqA01ti`g(9qsW|p?ok{UwFji} za`6*9c<_;Pn`GE_L%wS2gI5Ok=}_C5+rI70)`RXa)OZjhU0-w*^?;O`QRI8EptDCm zUhg*?$djEsfARWY+fHip0WW;kIuzU9W<&qDW$#A%b@=JQa!gzBy}R6+oJOk{*#9q{3K{L9ST z$?0ND%t*Wgnc~3?ft?VCever%V+)nm)6C`Y0uLi7HSu$dR%#gX$&D-Sud#}Uua$^z z>?_`u@XLScxL?}m6>Sy7EnoRgKJ-g)?=cWyT6;h$C8vPhdV^Hr$-F<4`>k8 zn8TZR64%ElD}C(d!-=`sjIo?O*zSl!2Q^Qokk1#LG*kw?70rCoREkylYz5&%eVjvT zJ=XUh+nw;ryVE|t-DCKX`E7wb-AnmVX5Bf`Ra7s_j_wUg88dje7T~3a;P-G@LZG0Z z@zUzM5RaMt9m> zQk?i%#pRMTRu6G8mlRC1B^rin?=NRhYjqrEIt0Y#fEBQ$S;+W|C`0o-m@@KaTk=FF zntAclWpGj0Tm@*}?v}_`gftlq@sRe)Sb%1WcIEb0bCOyrIQuk3ZE{_ooztR-TsvCYs-Au}3= zU#z4~UhNxCcmGut-r&+&U6qUkG*OrO?QdTc@$o)1d~DO1+^Ee!l$-TPtfrLUg(Y?K+)fF-bUM5t!U7Yz9_Sn9T{r+2c>?G0SxPN%l4h6aQWQ$GE1tuU~c&%O}zoZ->H zyKDl#%NH?;Dv&ok*xj%bBF*pdsATrUw??Yf=K1J1obd`(7`L?&w-5JSurdUk=Loyi zPj_b2pA;tzFCx&hTVwThlQZAXD}FppynC|dyDO)p`bJMi91BHKHn(`&+|$*(&CT&1 z&rDaK5a1}il8uswAvOaoinRtyfyuQaR-RT`rxH<7p-Sn=z*BRkCGNqEFb3Y7)qgtuQyaWOAt03f!u%Al{y%3I658duaP}IW zM?VF%D^Gu)?m|+#To-`3OTfP$@K1^D3J8~?;cnr6E@8iC?EgIPg%WkSF5Cm)A~t-V z|Inqbj(%CM{#2%}&j~4s{f2kYSJNz#S@1gzN;Yv05 z&*T588(cef{~dO%B3%3Z_c8H$gLm+$@#5sahQ@2?|2nb_ocmvW`WklW@y~{S?J@p$ z*gx(4PxPPtn+a literal 0 HcmV?d00001 diff --git a/TestScripts/deprecated/playwright/test-data/single_operation.xlsx b/TestScripts/deprecated/playwright/test-data/single_operation.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..999ecbe052a89becfd7285f77d119066dc06d92d GIT binary patch literal 6488 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