ee044d03e0
- Add /health endpoint with anonymous access for monitoring - Add FileUploadResult<T> model and PostMultipartForFileResultAsync for proper upload response handling - Add ApiResult.Success() factory method for interface types - Refactor Login.razor for cleaner code - Add comprehensive Playwright E2E test suite with fixtures and helpers
411 lines
15 KiB
TypeScript
411 lines
15 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { navigateToSearchPage } from '../helpers/navigation.helper';
|
|
import { selectSearchType, SearchTypes, enterSearchName, clickSubmitSearch, confirmSubmitSearch } from '../helpers/search-type.helper';
|
|
import { setDateRange, setMinDate, setMaxDate, clearDateRange, TestDateRanges } from '../helpers/date-picker.helper';
|
|
import {
|
|
addProfitCenter,
|
|
addProfitCenters,
|
|
clearAutocompleteItems,
|
|
profitCenterConfig,
|
|
getAutocompleteItemCount,
|
|
removeAutocompleteItem,
|
|
isAutocompletePanelVisible,
|
|
} from '../helpers/autocomplete.helper';
|
|
import { assertNoErrorNotification, hasSuccessNotification } from '../helpers/radzen.helper';
|
|
import { hasValidationErrors, submitAndExpectError, ValidationMessages } from '../helpers/validation.helper';
|
|
|
|
/**
|
|
* Test suite for Search Type 30: Time Span + Profit Center
|
|
*
|
|
* This search type allows users to search by a date range combined with
|
|
* one or more profit center (branch) codes.
|
|
*
|
|
* Filters Enabled: Timespan, Profit Center
|
|
*/
|
|
test.describe('Search Type 30: Time Span + Profit Center', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await navigateToSearchPage(page);
|
|
});
|
|
|
|
// ============================================================================
|
|
// POSITIVE TEST CASES
|
|
// ============================================================================
|
|
|
|
test.describe('Positive Tests', () => {
|
|
test('TC-030-P01: Single profit center with standard date range', async ({ page }) => {
|
|
// Select search type
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
|
|
// Verify filter panel is visible
|
|
await expect(page.locator('text=Filter by Profit Center')).toBeVisible();
|
|
await expect(page.locator('text=Filter by Time Span')).toBeVisible();
|
|
|
|
// Enter search name
|
|
await enterSearchName(page, 'TC-030-P01 Single Profit Center');
|
|
|
|
// Set date range
|
|
await setDateRange(page, '2020-01-01', '2020-09-01');
|
|
|
|
// Add profit center
|
|
await addProfitCenter(page, '1AM');
|
|
|
|
// Verify profit center appears in the list
|
|
const itemCount = await getAutocompleteItemCount(page, profitCenterConfig);
|
|
expect(itemCount).toBe(1);
|
|
|
|
// Submit search
|
|
await clickSubmitSearch(page);
|
|
await confirmSubmitSearch(page);
|
|
|
|
// Verify no error notification
|
|
await assertNoErrorNotification(page);
|
|
});
|
|
|
|
test('TC-030-P02: Multiple profit centers search', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-P02 Multiple Profit Centers');
|
|
|
|
// Set date range
|
|
await setDateRange(page, '2019-01-01', '2019-12-31');
|
|
|
|
// Add multiple profit centers
|
|
await addProfitCenters(page, ['1AM', '1PM', '2DM']);
|
|
|
|
// Verify all profit centers appear in the list
|
|
const itemCount = await getAutocompleteItemCount(page, profitCenterConfig);
|
|
expect(itemCount).toBe(3);
|
|
|
|
// Submit search
|
|
await clickSubmitSearch(page);
|
|
await confirmSubmitSearch(page);
|
|
|
|
await assertNoErrorNotification(page);
|
|
});
|
|
|
|
test('TC-030-P03: All profit centers search', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-P03 All Profit Centers');
|
|
|
|
// Set date range
|
|
await setDateRange(page, '2018-01-01', '2018-12-31');
|
|
|
|
// Add all profit centers
|
|
const allProfitCenters = ['1AM', '1BM', '1CM', '1PM', '2DM', '2SM', '3TM', '4IM', '5SM'];
|
|
await addProfitCenters(page, allProfitCenters);
|
|
|
|
// Verify all profit centers appear in the list
|
|
const itemCount = await getAutocompleteItemCount(page, profitCenterConfig);
|
|
expect(itemCount).toBe(9);
|
|
|
|
// Submit search
|
|
await clickSubmitSearch(page);
|
|
await confirmSubmitSearch(page);
|
|
|
|
await assertNoErrorNotification(page);
|
|
});
|
|
|
|
test('TC-030-P04: Minimum date range (same day)', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-P04 Same Day Range');
|
|
|
|
// Set same day date range
|
|
await setDateRange(page, TestDateRanges.SAME_DAY.min, TestDateRanges.SAME_DAY.max);
|
|
|
|
// Add profit center
|
|
await addProfitCenter(page, '1PM');
|
|
|
|
// Submit search
|
|
await clickSubmitSearch(page);
|
|
await confirmSubmitSearch(page);
|
|
|
|
await assertNoErrorNotification(page);
|
|
});
|
|
|
|
test('TC-030-P05: Boundary date - start of data range', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-P05 Start Boundary');
|
|
|
|
// Set earliest date boundary (1905-01-20 to 1905-12-31)
|
|
await setDateRange(page, TestDateRanges.START_BOUNDARY.min, TestDateRanges.START_BOUNDARY.max);
|
|
|
|
// Add profit center
|
|
await addProfitCenter(page, '1AM');
|
|
|
|
// Submit search
|
|
await clickSubmitSearch(page);
|
|
await confirmSubmitSearch(page);
|
|
|
|
await assertNoErrorNotification(page);
|
|
});
|
|
|
|
test('TC-030-P06: Boundary date - end of data range', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-P06 End Boundary');
|
|
|
|
// Set latest date boundary (2020-08-01 to 2020-09-01)
|
|
await setDateRange(page, TestDateRanges.END_BOUNDARY.min, TestDateRanges.END_BOUNDARY.max);
|
|
|
|
// Add profit center
|
|
await addProfitCenter(page, '1CM');
|
|
|
|
// Submit search
|
|
await clickSubmitSearch(page);
|
|
await confirmSubmitSearch(page);
|
|
|
|
await assertNoErrorNotification(page);
|
|
});
|
|
|
|
test('TC-030-P07: Historical date range search', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-P07 Historical Search');
|
|
|
|
// Set historical date range (2016-01-01 to 2017-12-31)
|
|
await setDateRange(page, TestDateRanges.HISTORICAL.min, TestDateRanges.HISTORICAL.max);
|
|
|
|
// Add profit center
|
|
await addProfitCenter(page, '2SM');
|
|
|
|
// Submit search
|
|
await clickSubmitSearch(page);
|
|
await confirmSubmitSearch(page);
|
|
|
|
await assertNoErrorNotification(page);
|
|
});
|
|
|
|
test('TC-030-P08: Profit center remove and re-add', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-P08 PC Remove Re-add');
|
|
|
|
// Set date range
|
|
await setDateRange(page, '2019-01-01', '2019-12-31');
|
|
|
|
// Add profit centers
|
|
await addProfitCenter(page, '1AM');
|
|
await addProfitCenter(page, '1BM');
|
|
|
|
// Verify both are added
|
|
let itemCount = await getAutocompleteItemCount(page, profitCenterConfig);
|
|
expect(itemCount).toBe(2);
|
|
|
|
// Remove first profit center (1AM)
|
|
await removeAutocompleteItem(page, profitCenterConfig, 0);
|
|
|
|
// Verify only one remains
|
|
itemCount = await getAutocompleteItemCount(page, profitCenterConfig);
|
|
expect(itemCount).toBe(1);
|
|
|
|
// Add another profit center
|
|
await addProfitCenter(page, '1CM');
|
|
|
|
// Verify two profit centers in list (1BM and 1CM)
|
|
itemCount = await getAutocompleteItemCount(page, profitCenterConfig);
|
|
expect(itemCount).toBe(2);
|
|
|
|
// Submit search
|
|
await clickSubmitSearch(page);
|
|
await confirmSubmitSearch(page);
|
|
|
|
await assertNoErrorNotification(page);
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// NEGATIVE TEST CASES
|
|
// ============================================================================
|
|
|
|
test.describe('Negative Tests', () => {
|
|
test('TC-030-N01: Missing search name', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
|
|
// Do NOT enter search name
|
|
|
|
// Set valid date range
|
|
await setDateRange(page, '2020-01-01', '2020-09-01');
|
|
|
|
// Add profit center
|
|
await addProfitCenter(page, '1AM');
|
|
|
|
// Attempt to submit
|
|
await submitAndExpectError(page);
|
|
|
|
// Verify user remains on the page
|
|
await expect(page.locator('text=Filter by Profit Center')).toBeVisible();
|
|
});
|
|
|
|
test('TC-030-N02: No search type selected', async ({ page }) => {
|
|
// Enter search name without selecting search type
|
|
await enterSearchName(page, 'TC-030-N02 No Type');
|
|
|
|
// Verify filter panels are not visible (search type not selected)
|
|
const profitCenterPanelVisible = await isAutocompletePanelVisible(page, profitCenterConfig);
|
|
expect(profitCenterPanelVisible).toBe(false);
|
|
|
|
// Attempt to submit
|
|
await submitAndExpectError(page);
|
|
});
|
|
|
|
test('TC-030-N03: Missing minimum date', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-N03 Missing Min Date');
|
|
|
|
// Only set maximum date
|
|
await setMaxDate(page, '2020-09-01');
|
|
|
|
// Add profit center
|
|
await addProfitCenter(page, '1AM');
|
|
|
|
// Attempt to submit
|
|
await submitAndExpectError(page);
|
|
});
|
|
|
|
test('TC-030-N04: Missing maximum date', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-N04 Missing Max Date');
|
|
|
|
// Only set minimum date
|
|
await setMinDate(page, '2020-01-01');
|
|
|
|
// Add profit center
|
|
await addProfitCenter(page, '1AM');
|
|
|
|
// Attempt to submit
|
|
await submitAndExpectError(page);
|
|
});
|
|
|
|
test('TC-030-N05: Empty profit center list', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-N05 Empty Profit Centers');
|
|
|
|
// Set valid date range
|
|
await setDateRange(page, '2020-01-01', '2020-09-01');
|
|
|
|
// Do NOT add any profit centers
|
|
|
|
// Verify profit center list is empty
|
|
const itemCount = await getAutocompleteItemCount(page, profitCenterConfig);
|
|
expect(itemCount).toBe(0);
|
|
|
|
// Attempt to submit
|
|
await submitAndExpectError(page);
|
|
});
|
|
|
|
test('TC-030-N06: Invalid date range (min > max)', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-N06 Invalid Date Range');
|
|
|
|
// Set invalid date range (min date after max date)
|
|
await setDateRange(page, TestDateRanges.INVALID_REVERSED.min, TestDateRanges.INVALID_REVERSED.max);
|
|
|
|
// Add profit center
|
|
await addProfitCenter(page, '1AM');
|
|
|
|
// Attempt to submit
|
|
await submitAndExpectError(page);
|
|
});
|
|
|
|
test('TC-030-N07: Invalid profit center code', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-N07 Invalid PC Code');
|
|
|
|
// Set valid date range
|
|
await setDateRange(page, '2020-01-01', '2020-09-01');
|
|
|
|
// Try to add invalid profit center
|
|
// The autocomplete should not find any matches for "INVALID"
|
|
const panel = page.locator(`.rz-card:has-text("${profitCenterConfig.panelHeader}")`);
|
|
const autocomplete = panel.locator('.rz-autocomplete input');
|
|
await autocomplete.fill('INVALID');
|
|
|
|
// Wait for autocomplete to search
|
|
await page.waitForTimeout(500);
|
|
|
|
// Verify no autocomplete suggestions appear
|
|
const dropdown = page.locator('.rz-autocomplete-list');
|
|
const dropdownVisible = await dropdown.isVisible({ timeout: 2000 }).catch(() => false);
|
|
|
|
// If dropdown is not visible or empty, the invalid code is rejected
|
|
if (dropdownVisible) {
|
|
const items = dropdown.locator('.rz-autocomplete-list-item');
|
|
const count = await items.count();
|
|
expect(count).toBe(0);
|
|
}
|
|
|
|
// Verify profit center list is still empty
|
|
const itemCount = await getAutocompleteItemCount(page, profitCenterConfig);
|
|
expect(itemCount).toBe(0);
|
|
});
|
|
|
|
test('TC-030-N08: Future date range', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-N08 Future Dates');
|
|
|
|
// Set future date range
|
|
await setDateRange(page, TestDateRanges.FUTURE.min, TestDateRanges.FUTURE.max);
|
|
|
|
// Add profit center
|
|
await addProfitCenter(page, '1AM');
|
|
|
|
// Submit search - may be accepted but will return no results
|
|
// or may show validation warning
|
|
await clickSubmitSearch(page);
|
|
|
|
// Check if there's a validation error or if it proceeds
|
|
const hasErrors = await hasValidationErrors(page);
|
|
if (!hasErrors) {
|
|
// If accepted, confirm the submission
|
|
await confirmSubmitSearch(page);
|
|
await assertNoErrorNotification(page);
|
|
}
|
|
// If there are validation errors, that's also acceptable behavior
|
|
});
|
|
|
|
test('TC-030-N09: Invalid date format', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-N09 Invalid Date Format');
|
|
|
|
// Try to enter invalid date format directly
|
|
// The Radzen date picker should prevent or reject invalid formats
|
|
const minDateInput = page.locator('input[name="MinimumDt"]');
|
|
await minDateInput.fill('31-12-2020'); // Invalid format
|
|
|
|
await setMaxDate(page, '2020-09-01');
|
|
|
|
// Add profit center
|
|
await addProfitCenter(page, '1AM');
|
|
|
|
// Attempt to submit - should fail validation
|
|
await submitAndExpectError(page);
|
|
});
|
|
|
|
test('TC-030-N10: Profit center with special characters', async ({ page }) => {
|
|
await selectSearchType(page, SearchTypes.TIMESPAN_PROFIT_CENTER);
|
|
await enterSearchName(page, 'TC-030-N10 PC Special Chars');
|
|
|
|
// Set valid date range
|
|
await setDateRange(page, '2020-01-01', '2020-09-01');
|
|
|
|
// Try to add profit center with special characters
|
|
const panel = page.locator(`.rz-card:has-text("${profitCenterConfig.panelHeader}")`);
|
|
const autocomplete = panel.locator('.rz-autocomplete input');
|
|
await autocomplete.fill('1AM!@#');
|
|
|
|
// Wait for autocomplete to search
|
|
await page.waitForTimeout(500);
|
|
|
|
// Verify no autocomplete suggestions appear for invalid input
|
|
const dropdown = page.locator('.rz-autocomplete-list');
|
|
const dropdownVisible = await dropdown.isVisible({ timeout: 2000 }).catch(() => false);
|
|
|
|
if (dropdownVisible) {
|
|
const items = dropdown.locator('.rz-autocomplete-list-item');
|
|
const count = await items.count();
|
|
expect(count).toBe(0);
|
|
}
|
|
|
|
// Verify profit center list is still empty
|
|
const itemCount = await getAutocompleteItemCount(page, profitCenterConfig);
|
|
expect(itemCount).toBe(0);
|
|
});
|
|
});
|
|
});
|