diff --git a/playwright-tests/business-logic/Data/PaymentData.ts b/playwright-tests/business-logic/Data/PaymentData.ts deleted file mode 100644 index 699a2eeb9..000000000 --- a/playwright-tests/business-logic/Data/PaymentData.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { IPaymentDetails } from "@business-logic/types/CustomerDetails"; -import { PaymentType } from "@business-logic/types/Enums"; - -const defaultCreditCardDetails: IPaymentDetails = { - paymentType: PaymentType.Credit, - cardNumber: '4111111111111111', - expirationMonth: '12 - December', - expirationYear: '2029', - cvv: '555', - billingAddress: { - street: '2088 Tuller St', - city: 'Columbus', - state: 'OH', - postalCode: '43028', - country: 'US' - } -} - -const defaultAfterpayDetails: IPaymentDetails = { - paymentType: PaymentType.AfterPay, - username: 'itqatest@safelite.com', - password: 'Safelite1', - cardNumber: '4111 1111 1111 1111', - expirationMonth: '12', - expirationYear: '34', - cvv: '000' -} - -const defaultPaypalDetails: IPaymentDetails = { - paymentType: PaymentType.Paypal, - username: 'itqatest@safelite.com', - password: 'Safelite1' -} - -export default class PaymentData { - - static getDefaultCreditCardDetails() { - return defaultCreditCardDetails; - } - - static getDefaultAfterpayDetails() { - return defaultAfterpayDetails; - } - - static getDefaultPaypalDetails() { - return defaultPaypalDetails; - } -} \ No newline at end of file diff --git a/playwright-tests/business-logic/constants/DefaultTestData.ts b/playwright-tests/business-logic/constants/DefaultTestData.ts deleted file mode 100644 index 197297b4b..000000000 --- a/playwright-tests/business-logic/constants/DefaultTestData.ts +++ /dev/null @@ -1,114 +0,0 @@ -// DefaultTestData.ts -import { faker } from "@faker-js/faker"; -import { PaymentMethod, ServicePackage, VehicleLookupType, AppointmentType, PaymentType, DamageType, VehicleDamage } from "@business-logic/types/Enums"; -import { ITestData } from "@business-logic/types/ITestData"; -import { getNextWeekday } from "@impl/utils/DateUtils"; -import { ICustomerDetails, IVehicleDetails, IAppointmentDetails, IPaymentDetails, IClaimDetails } from "@business-logic/types/CustomerDetails"; - -// Set a default seed for consistent data generation -const DEFAULT_SEED = 1234; -faker.seed(DEFAULT_SEED); - -// Function to reset faker to the default seed -export function resetFakerToDefaultSeed() { - faker.seed(DEFAULT_SEED); -} - -// Simple hash function to convert a string to a numeric value -function hashStringToNumber(str: string): number { - let hash = 0; - for (let i = 0; i < str.length; i++) { - const char = str.charCodeAt(i); - hash = (hash << 5) - hash + char; - hash = hash & hash; // Convert to 32bit integer - } - return Math.abs(hash); -} - -// Function to set a custom seed based on test name -export function setFakerSeedFromTestName(testName: string) { - const seed = hashStringToNumber(testName); - faker.seed(seed); -} - -// Functions to generate data (rather than using pre-generated data) -export function getCustomerDetails(): ICustomerDetails { - return { - firstName: faker.person.firstName(), - lastName: faker.person.lastName(), - email: "itqatest@safelite.com", - phoneNumber: '614-254-4109', - notes: 'Automated Test', - address: { - street: faker.location.streetAddress(), - city: 'Columbus', - state: 'Ohio', - postalCode: '21237', - country: 'United States' - } - }; -} - -export function getVehicleDetails(): IVehicleDetails { - return { - year: '2020', - make: 'Honda', - model: 'Accord', - style: '4 door sedan', - vehicleLookupType: VehicleLookupType.Zip - }; -} - -export function getAppointmentDetails(): IAppointmentDetails { - return { - serviceLocation: AppointmentType.InShop, - appointmentDate: getNextWeekday() - }; -} - -export function getPaymentDetails(): IPaymentDetails { - return { - paymentType: PaymentType.PayAtService - }; -} - -export function getClaimDetails(): IClaimDetails { - return { - client: 'ACUITY INSURANCE', - policyNumber: 'Mock' + faker.string.alphanumeric(6).toUpperCase(), - policyDeductible: 0, - damageDate: new Date(new Date().setDate(new Date().getDate() - 1)).toLocaleDateString('en-US', {month: '2-digit', day: '2-digit', year: 'numeric'}), - damageCause: DamageType.Hail - }; -} - -// Function to get the entire default test data set with current faker state -export function getDefaultTestData(): Partial { - return { - paymentMethod: PaymentMethod.SelfPay, - servicePackage: ServicePackage.GlassOnly, - customerDetails: getCustomerDetails(), - vehicleDetails: getVehicleDetails(), - appointmentDetails: getAppointmentDetails(), - paymentDetails: getPaymentDetails(), - claimDetails: getClaimDetails(), - vehicleDamage: [VehicleDamage.WindshieldCrack], - isDuplicateClaim: false, - isPolicyDriver: false, - isPolicyFound: false, - isUseVehicleOnPolicy: true, - isRecalNotification: false, - hasOemEndorsement: false, - skipEstimatePage: false, - isRecalVehicle: false, - enterFunnelWithZip: false - }; -} - -// Keep the pre-generated data for backward compatibility -export const defaultCustomerDetails = getCustomerDetails(); -export const defaultVehicleDetails = getVehicleDetails(); -export const defaultAppointmentDetails = getAppointmentDetails(); -export const defaultPaymentDetails = getPaymentDetails(); -export const defaultClaimDetails = getClaimDetails(); -export const defaultTestData = getDefaultTestData(); \ No newline at end of file diff --git a/playwright-tests/business-logic/constants/StateAbbreviation.ts b/playwright-tests/business-logic/constants/StateAbbreviation.ts deleted file mode 100644 index f0fc95d79..000000000 --- a/playwright-tests/business-logic/constants/StateAbbreviation.ts +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Mapping of state names to their two-letter abbreviations - */ -export const STATE_ABBREVIATIONS: Record = { - 'Alabama': 'AL', - 'Alaska': 'AK', - 'Arizona': 'AZ', - 'Arkansas': 'AR', - 'California': 'CA', - 'Colorado': 'CO', - 'Connecticut': 'CT', - 'Delaware': 'DE', - 'District of Columbia': 'DC', - 'Florida': 'FL', - 'Georgia': 'GA', - 'Hawaii': 'HI', - 'Idaho': 'ID', - 'Illinois': 'IL', - 'Indiana': 'IN', - 'Iowa': 'IA', - 'Kansas': 'KS', - 'Kentucky': 'KY', - 'Louisiana': 'LA', - 'Maine': 'ME', - 'Maryland': 'MD', - 'Massachusetts': 'MA', - 'Michigan': 'MI', - 'Minnesota': 'MN', - 'Mississippi': 'MS', - 'Missouri': 'MO', - 'Montana': 'MT', - 'Nebraska': 'NE', - 'Nevada': 'NV', - 'New Hampshire': 'NH', - 'New Jersey': 'NJ', - 'New Mexico': 'NM', - 'New York': 'NY', - 'North Carolina': 'NC', - 'North Dakota': 'ND', - 'Ohio': 'OH', - 'Oklahoma': 'OK', - 'Oregon': 'OR', - 'Pennsylvania': 'PA', - 'Rhode Island': 'RI', - 'South Carolina': 'SC', - 'South Dakota': 'SD', - 'Tennessee': 'TN', - 'Texas': 'TX', - 'Utah': 'UT', - 'Vermont': 'VT', - 'Virginia': 'VA', - 'Washington': 'WA', - 'West Virginia': 'WV', - 'Wisconsin': 'WI', - 'Wyoming': 'WY', - }; - - /** - * Gets the two-letter abbreviation for a state name - * @param stateName Full state name - * @returns Two-letter abbreviation - * @throws Error if state name is not found - */ - export function getStateAbbreviation(stateName: string): string { - const abbreviation = STATE_ABBREVIATIONS[stateName]; - if (!abbreviation) { - throw new Error(`State "${stateName}" not found in mapping`); - } - return abbreviation; - } \ No newline at end of file diff --git a/playwright-tests/business-logic/rules/RuleEngineBuiltins.ts b/playwright-tests/business-logic/rules/RuleEngineBuiltins.ts deleted file mode 100644 index f9f1adf01..000000000 --- a/playwright-tests/business-logic/rules/RuleEngineBuiltins.ts +++ /dev/null @@ -1,44 +0,0 @@ -import TestCase from "@business-logic/types/TestCase"; -import { Rule } from "../types/RuleEngine"; -import EnumUtils from "../../impl/utils/EnumUtils"; - -// File containing Rule Engine Builtin Rules for JSON Data Validation - -export enum BuiltInRules { - //Custom Rules -} - -// Built-Ins shouldn't depend on other rules, custom rules however are supposed to depend on them -export const builtInRules: Rule[] = -[ -//{ -// id: BuiltInRules.TransactionExists, -// name: "Transaction Exists Rule", -// check: (testCase: TestCase) => { -// return testCase.transaction != null; -// } -// }, { -// id: BuiltInRules.PricingExists, -// name: "Pricing must exist on Transaction Rule", -// check: (testCase: TestCase) => { -// return testCase.transaction != null && testCase.transaction.pricing != null; -// } -// }, { -// id: BuiltInRules.TerminationIsMod, -// name: "OpportunityType Termination requires TransactionSubType Mod", -// check: (testCase: TestCase) => { - -// // Check old transactions -// for (var transaction of testCase.oldTransactions) { -// if (transaction.opportunityType == OpportunityTypes.Termination) -// return transaction.subType == TransactionSubTypes.Mod; -// } - -// // Check transaction -// if (testCase.transaction.opportunityType == OpportunityTypes.Termination) -// return testCase.transaction.subType == TransactionSubTypes.Mod; -// return true; -// }, -// dependsOn: [BuiltInRules.TransactionExists] -// }, { -]; \ No newline at end of file diff --git a/playwright-tests/business-logic/types/Authentication.ts b/playwright-tests/business-logic/types/Authentication.ts deleted file mode 100644 index 0b3400737..000000000 --- a/playwright-tests/business-logic/types/Authentication.ts +++ /dev/null @@ -1 +0,0 @@ -// File for interfaces related to authentication \ No newline at end of file diff --git a/playwright-tests/business-logic/types/CustomerDetails.ts b/playwright-tests/business-logic/types/CustomerDetails.ts deleted file mode 100644 index 3ac2747a0..000000000 --- a/playwright-tests/business-logic/types/CustomerDetails.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { DamageType as DamageCause, WindshieldDamage, ServiceLocation, EndorsementType, VehicleLookupType, PartQuestionType, PaymentType, AppointmentType, AppointmentTimeslot } from "./Enums"; -import { IAddress } from "./IAddress"; - -export interface ICustomerDetails { - firstName: string, - lastName: string, - email: string, - phoneNumber: string, - notes: string, - address: IAddress, - apptDate?: string, - apptTime?: string, - apptDuration?: string, - packagePrice?: string -} - -export interface IVehicleDetails { - year: string, - make: string, - model: string, - style?: string, - vin?: string, - licensePlateNumber?: string, - licensePlateState?: string, - vehicleLookupType: VehicleLookupType, -} - -export interface IAppointmentDetails { - serviceLocation: AppointmentType, - appointmentDate?: Date, - shopAddress?: string, // Used for in-shop - serviceAddress?: IAddress, // Used for mobile - isVehicleProtected?: boolean, - appointmentTimeSlot?: AppointmentTimeslot // Used for mobile -} - -export interface IEndorsementDetails { - endorsementType: EndorsementType, - isOnPolicy: boolean, // Should we expect this endorsement to appear? - isClickYes: boolean // Should we click Yes or No? -} - -export interface IPartQuestion { - isOnPage: boolean, - optionToSelect: string, - partQuestionType: PartQuestionType, - secondaryQuestionOptionToSelect?: string -} - -export interface IPaymentDetails { - paymentType?: PaymentType, - username?: string, - password?: string, - cardNumber?: string, - expirationMonth?: string, - expirationYear?: string, - cvv?: string, - billingAddress?: IAddress, -} - -export interface IClaimDetails { - client: string, - policyNumber: string, - policyDeductible: number, - policyZip?: string - damageDate: string, - damageCause: DamageCause -} - diff --git a/playwright-tests/business-logic/types/DigitalAPI.ts b/playwright-tests/business-logic/types/DigitalAPI.ts deleted file mode 100644 index 7317639df..000000000 --- a/playwright-tests/business-logic/types/DigitalAPI.ts +++ /dev/null @@ -1,38 +0,0 @@ -export interface IPartsOrQuestionsResponse { - partsOrQuestions: IPartOrQuestion[] -} - -export interface IPartOrQuestion { - glassPiece: IGlassPiece, - parts: IPart[], - partQuestions: IPartQuestion[] | null; -} - -export interface IGlassPiece { - name: string, - location: string -} - -export interface IPart { - childPartQuestions: IPartQuestion[], - basePartNumber: string, - safelitePartNumber: string, - color: string, - requiresRecalibration: boolean, - recalibrationType: null, // TODO: Add types - canSafeliteRecalibrate: boolean, - requiresCapabilityQuestions: boolean, - childParts: IChildPart[], - partNumber: string, - description: string, - partType: string -} - -export interface IPartQuestion { - // TODO: Define -} - -export interface IChildPart { - partNumber: string, - safelitePartNumber: string -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/Enums.ts b/playwright-tests/business-logic/types/Enums.ts deleted file mode 100644 index a2d633dab..000000000 --- a/playwright-tests/business-logic/types/Enums.ts +++ /dev/null @@ -1,155 +0,0 @@ -// Enums File - -export enum ConsoleColor { - Default = "", - Red = "\x1b[31m", - Green = "\x1b[32m", - Yellow = "\x1b[33m", - Orange = "\x1b[202m", - Blue = "\x1b[34m", - Magenta = "\x1b[35m", - Cyan = "\x1b[36m", - Reset = "\x1b[0m" -} - -export enum ResultTypes { - None = 0, - Skipped = 1, - Success = 2, - Failure = 3 -} - -export enum VehicleLookupType { - Vin, - Address, - LicensePlateNumber, - Zip -} - -export enum VehicleDamage { - WindshieldOneChip = "WINDSHIELD ONE CHIP", - WindshieldTwoChips = "WINDSHIELD TWO CHIPS", - WindshieldThreeChips = "WINDSHIELD THREE CHIPS", - WindshieldCrack = "WINDSHIELD", - RearWindow = "BACK GLASS", - RearSliding = "SLIDER", - DriverFrontDoor = "DRIVER FRONT DOOR GLASS", - DriverRearDoor = "DRIVER REAR DOOR GLASS", - DriverVentGlass = "DRIVER VENT GLASS", - DriverQuarterPanel = "DRIVER REAR QUARTER GLASS", - DriverSlidingDoor = "DRIVER SLIDING DOOR GLASS", - PassengerFrontDoor = "PASSENGER FRONT DOOR GLASS", - PassengerRearDoor = "PASSENGER REAR DOOR GLASS", - PassengerVentGlass = "PASSENGER VENT GLASS", - PassengerQuarterPanel = "PASSENGER REAR QUARTER GLASS" -} - -export enum WindshieldDamage{ - Crack, - OneChip, - TwoChips, - ThreeChips -} - -export enum SideDoorDamage{ - Passenger = "Passenger", - Driver = "Driver" -} - -export enum DamageType { - Rock = 'Rock from road', - Vandalism = 'Vandalism', - Theft = 'Attempted theft or theft', - Hail = 'Hail storm', - HurricaneStorm = 'Hurricane/Storm', - OtherWeather = 'Other weather', - Collision = 'Collision', - Object = 'Object hit glass', - Other = 'Other/unknown' -} - -export enum ServiceLocation { - Mobile, - InShop, - DropOff -} - -export enum ServicePackage { - GlassOnly = 'Glass service only', - Standard = 'Standard', - Premium = 'Premium' -} - -export enum EndorsementType { - Educator = '01', - EmployeeParking = '03' -} - -export enum PartQuestionType { - WindshieldColor = 'Windshield-Single', - DriverFrontColor = 'Driver-Front', - DriverQuarterColor = 'Driver-Quarter', - DriverRearColor = 'Driver-Back', - DriverVentColor = 'Driver-Vent', - PassengerFrontColor = 'Passenger-Front', - PassengerQuarterColor = 'Passenger-Quarter', - PassengerRearColor = 'Passenger-Back', - PassengerVentColor = 'Passenger-Vent', - RearWindowColor = 'Rear-Stationary', - RearSlidingWindowColor = 'Rear-Slider', - DriverSideColor = 'Driver-SideDoor', - // use generalized tag for other part questions - GeneralQuestion1 = 'question-0-1', - GeneralQuestion2 = 'question-0-2', - GeneralQuestion3 = 'question-0-3', - GeneralQuestion4 = 'question-0-4' -} - -export enum PaymentType{ - Credit = "Credit", - AfterPay = "AfterPay", - Paypal = "Paypal", - PayAtService = "Pay at Service", - PayWithInsurance = "Pay with Insurance" -} - -export enum PaymentMethod { - Insurance = 'Insurance', - SelfPay = 'SelfPay' -} - -export enum AppointmentType{ - InShop = "InShop", - Mobile = "Mobile", - DropOff = "Drop-off" -} - -export enum AppointmentTimeslot{ - EarlyBird = "EarlyBird", - DropOff = "DropOff", - overnight = "Overnight" -} - -export enum ProgressBarPercentages { - VehicleSelectionPage = '4%', - VehicleDamagePage = '16%', - EstimatePage = '28%', - ServiceZipPage = '32%', - VehicleLookupAddressPage = '32%', - VehicleLookupLicensePage = '32%', - VinLookupPage = '32%', - PartQuestionsPage = '40%', - MoldingQuestionsPage = '40%', - CapabilityQuestionsPage = '40%', - VehiclePartsPage = '40%', - ServicePackagePage = '48%', - InsuranceCompanyPage = '52%', - ServiceLocationPage = '60%', - SchedulePage = '72%', - ContactDetailsPage = '84%', - PaymentMethodPage = '92%', - OrderConfirmationPage = '100%' - } - - - diff --git a/playwright-tests/business-logic/types/FrameworkConfig.ts b/playwright-tests/business-logic/types/FrameworkConfig.ts deleted file mode 100644 index 63a744b93..000000000 --- a/playwright-tests/business-logic/types/FrameworkConfig.ts +++ /dev/null @@ -1,9 +0,0 @@ -// File for Framework Config - -type FrameworkConfig = { - createResources: boolean; - destroyResources: boolean; - maxAllotmentHours: number; -}; - -export default FrameworkConfig; \ No newline at end of file diff --git a/playwright-tests/business-logic/types/IAddress.ts b/playwright-tests/business-logic/types/IAddress.ts deleted file mode 100644 index 44b6577ef..000000000 --- a/playwright-tests/business-logic/types/IAddress.ts +++ /dev/null @@ -1,9 +0,0 @@ -// File with address interface - -export interface IAddress { - street: string, - city: string, - state: string, - postalCode: string, - country: string -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/IAlertFlags.ts b/playwright-tests/business-logic/types/IAlertFlags.ts deleted file mode 100644 index b13f30bbc..000000000 --- a/playwright-tests/business-logic/types/IAlertFlags.ts +++ /dev/null @@ -1,10 +0,0 @@ -export default interface IAlertFlags { - isHeavyTruckVehicle?: boolean, - isRepairReplace?: boolean, - isSplitWindshield?: boolean, - isRepairOnly?: boolean, - isUnserviceableZip?: boolean, - isInvalidZip?: boolean, - isVinNotFound?: boolean - -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/IDisposable.ts b/playwright-tests/business-logic/types/IDisposable.ts deleted file mode 100644 index 46e1a1ac9..000000000 --- a/playwright-tests/business-logic/types/IDisposable.ts +++ /dev/null @@ -1,31 +0,0 @@ -import LoggingUtils from "@impl/utils/LoggingUtils"; -import { ConsoleColor } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; - -// File with interfaces/classes related to Disposable - -export interface IDisposable { - disposeAll(): void; - setupAll(): void; -} - -export abstract class DisposableBase implements IDisposable { - protected abstract setup(): Promise; - protected abstract dispose(): Promise; - - public async setupAll(): Promise { - if (!TestCase.FrameworkConfig.destroyResources) { - LoggingUtils.log(TestCase.Constants.CREATION_HALTED, ConsoleColor.Yellow); - return; - } - await this.setup(); - } - - public async disposeAll(): Promise { - if (!TestCase.FrameworkConfig.destroyResources || !TestCase.FrameworkConfig.createResources) { - LoggingUtils.log(TestCase.Constants.DISPOSE_HALTED, ConsoleColor.Yellow); - return; - } - await this.dispose(); - } -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/ITestCase.ts b/playwright-tests/business-logic/types/ITestCase.ts deleted file mode 100644 index 3afbfd0db..000000000 --- a/playwright-tests/business-logic/types/ITestCase.ts +++ /dev/null @@ -1,18 +0,0 @@ -import ITestPages from "@business-logic/types/ITestPages"; -import Validations from "./Validations"; -import { ITestData } from "./ITestData"; - -// File containing Test Case Interface - -export default interface ITestCase { - readonly testID?: string; - readonly name: string; - readonly tags: string[]; - - readonly validations?: Validations; - readonly tempData?: any[] - - readonly testData: Partial; - - pages?: ITestPages; -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/ITestData.ts b/playwright-tests/business-logic/types/ITestData.ts deleted file mode 100644 index 76d0e4534..000000000 --- a/playwright-tests/business-logic/types/ITestData.ts +++ /dev/null @@ -1,36 +0,0 @@ -// File for the Test Data Structure - -import { IAppointmentDetails, IClaimDetails, ICustomerDetails, IPaymentDetails, IVehicleDetails, IPartQuestion, IEndorsementDetails } from "./CustomerDetails"; -import { PaymentMethod, ServicePackage, VehicleDamage } from "./Enums"; -import IAlertFlags from "./IAlertFlags"; - -export interface ITestData { - - paymentMethod: PaymentMethod - servicePackage: ServicePackage, - customerDetails: ICustomerDetails, - vehicleDetails: IVehicleDetails, - vehicleDamage: VehicleDamage[], - appointmentDetails: IAppointmentDetails, - paymentDetails: IPaymentDetails, - claimDetails: IClaimDetails, - alertFlags: IAlertFlags, - partQuestions: IPartQuestion[], // part-questions page has unrelated part questions like leather seats - vehiclePartQuestions: IPartQuestion[], // vehicle-parts page usually has glass question - capabilityQuestions: IPartQuestion[], // Capability questions page usually has questions about autonomous driving features - moldingQuestions: IPartQuestion[], - enterFunnelWithZip: boolean, - isDuplicateClaim: boolean, - isPolicyDriver: boolean, // Does the Policy Driver Page show up for the insurance claim? - isPolicyFound: boolean, - otherVehiclesOnPolicy: IVehicleDetails[], // IF defined, we validate that the vehicles are present. - isUseVehicleOnPolicy: boolean, // Should we use the vehicle on the policy? - isRecalNotification: boolean, // Does Recalibration Information page show up? - endorsements: IEndorsementDetails[], - hasOemEndorsement: boolean, // OEM Endorsement does not appear on endorsements page, so it has a separate flag.s - skipEstimatePage: boolean, - isRecalVehicle: boolean, - canNotRecal: boolean, - dynamicRecal: boolean, - promoCode: string -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/ITestPages.ts b/playwright-tests/business-logic/types/ITestPages.ts deleted file mode 100644 index d8ba7e5bd..000000000 --- a/playwright-tests/business-logic/types/ITestPages.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { HomePage } from "../../pages/HomePage" -import { LeadgenHomePage } from "../../pages/LeadgenHomePage" -import { ServicePackagesPage } from "../../pages/ServicePackagesPage" -import { VehicleDamagePage } from "../../pages/VehicleDamagePage" -import { VehicleLookupAddressPage } from "../../pages/VehicleLookupAddressPage" -import { VehicleLookupLicensePage } from "../../pages/VehicleLookupLicensePage" -import { EstimatePage } from "../../pages/EstimatePage" -import { VehicleSelectionPage } from "../../pages/VehicleSelectionPage" -import { VinLookupPage } from "../../pages/VinLookupPage" -import { ServiceLocationPage } from "../../pages/ServiceLocationPage" -import { SchedulePage } from "../../pages/SchedulePage" -import { ContactDetailsPage } from "../../pages/ContactDetailsPage" -import { PaymentMethodPage } from "../../pages/PaymentMethodPage" -import { ZipLookupPage } from "../../pages/ZipLookupPage" -import { OrderConfirmationPage } from "../../pages/OrderConfirmationPage" -import { PartQuestionsPage } from "../../pages/PartQuestionPage" -import VehiclePartQuestionsPage from "../../pages/VehiclePartsPage" -import CapabilityQuestionsPage from "../../pages/CapabilityQuestionsPage" -import MoldingQuestionsPage from "../../pages/MoldingQuestionsPage" -import { InsuranceCompanyPage } from "../../pages/InsuranceCompanyPage" -import { CCPolicyInfoPage } from "../../pages/CCPolicyInfoPage" -import { DuplicateCheckPage } from "../../pages/DuplicateCheckPage" -import { PolicyVehiclesPage } from "../../pages/PolicyVehiclesPage" -import { PolicyInfoSubmittedPage } from "../../pages/PolicyInfoSubmittedPage" -import RecalibrationInfoPage from "../../pages/RecalibrationInfoPage" -import { CoverageStatementPage } from "../../pages/CoverageStatementPage" -import { VerifyDetailsPage } from "../../pages/VerifyDetailsPage" -import { EndorsementsPage } from "../../pages/EndorsementsPage" -import { PolicyDriverPage } from "../../pages/PolicyDriverPage" -import { ServiceZipPage } from "../../pages/ServiceZipPage" -// File containing interface for all Page Object Models - -export default interface ITestPages { - capabilityQuestionsPage: CapabilityQuestionsPage, - ccPolicyInfoPage: CCPolicyInfoPage, - contactDetailsPage: ContactDetailsPage, - coverageStatementPage: CoverageStatementPage, - duplicateCheckPage: DuplicateCheckPage, - estimatePage: EstimatePage, - homePage: HomePage, - insuranceCompanyPage: InsuranceCompanyPage, - leadgenHomePage: LeadgenHomePage, - moldingQuestionsPage: MoldingQuestionsPage, - orderConfirmationPage: OrderConfirmationPage, - partQuestionsPage: PartQuestionsPage, - paymentMethodPage: PaymentMethodPage, - policyInfoSubmittedPage: PolicyInfoSubmittedPage, - policyVehiclesPage: PolicyVehiclesPage, - recalibrationInfoPage: RecalibrationInfoPage, - schedulePage: SchedulePage, - serviceLocationPage: ServiceLocationPage, - servicePackagesPage: ServicePackagesPage, - serviceZipPage: ServiceZipPage, - vehicleDamagePage: VehicleDamagePage, - vehicleLookupAddressPage: VehicleLookupAddressPage, - vehicleLookupLicensePage: VehicleLookupLicensePage, - vehiclePartsPage: VehiclePartQuestionsPage, - vehicleSelectionPage: VehicleSelectionPage, - verifyDetailsPage: VerifyDetailsPage, - vinLookupPage: VinLookupPage, - zipLookupPage: ZipLookupPage, - endorsementsPage: EndorsementsPage, - policyDriverPage: PolicyDriverPage, -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/IValidations.ts b/playwright-tests/business-logic/types/IValidations.ts deleted file mode 100644 index 4faa6f7a3..000000000 --- a/playwright-tests/business-logic/types/IValidations.ts +++ /dev/null @@ -1,5 +0,0 @@ -// File containing interface for validations - -export default interface IValidations { - -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/JiraApi.ts b/playwright-tests/business-logic/types/JiraApi.ts deleted file mode 100644 index af0ec7dfb..000000000 --- a/playwright-tests/business-logic/types/JiraApi.ts +++ /dev/null @@ -1,135 +0,0 @@ -export interface PutEditIssueRequestBody { - fields: Partial -} - -export interface PostTransitionIssueRequestBody { - transition: { id: string } -} - -export interface PostCreateIssueRequestBody extends JiraIssue {} - -export interface PostCreateIssueResponse { - id: string, - key: string -} - -export interface PostBulkCreateIssueRequestBody { - issueUpdates: PostCreateIssueRequestBody[] -} - -export interface BulkTransitionInput { - selectedIssueIdsOrKeys: string[], - transitionId: string -} - -export interface PostBulkTransitionIssuesRequestBody { - bulkTransitionInputs: BulkTransitionInput[], - sendBulkNotification: false -} - -export interface PostBulkCreateIssueResponse { - issues: PostCreateIssueResponse[] -} - -export interface PostAddCommentResponse { - body: JiraContent -} - -export interface JiraIssueFields { - summary: string, - description: JiraContent, - project?: JiraProject, - issuetype?: { id: string }, - parent?: JiraParent, - fixVersions?: JiraVersion[], - subtasks?: JiraSubTask[], - customfield_14857?: JiraContent, // Test Steps field - customfield_10007?: number // Sprint field, - customfield_13100?: { id: string } // UAT Tester ID field - -} - -export interface JiraSubTask { - id: string, - key: string -} - -export interface JiraProject { - key: string -} - -export interface JiraParent { - key: string -} - -export interface JiraContent { - type?: string, - text?: string, - version?: number - content?: JiraContent[] -} - -export interface JiraVersion { - id: string -} - -export interface JiraTransition { - id: string, - name: string -} - -export interface JiraIssueType { - id: string, - self: string, - description: string, - iconUrl: string, - name: string, - untranslatedName: string, - subtask: boolean, -} - -export interface GetIssueTransitionsResponse { - transitions: JiraTransition[] -} - -export interface GetIssueTypesResponse { - issueTypes: JiraIssueType[] -} - -export interface PostBulkFetchIssuesRequestBody { - issueIdsOrKeys: string[] -} - -export interface PostBulkFetchIssuesResponse { - issues: GetIssueResponse[]; -} - -export interface JiraIssue { - key?: string, - id?: string, - transition?: { id: string }, - fields: JiraIssueFields -} - -export interface GetIssueResponse extends JiraIssue {} - -export interface GetBoardResponse { - id: number, - name: string -} - -export interface GetSprintResponse { - values: JiraSprint[] -} - -export interface GetJqlSearchIssueParams { - jql: string -} - -export interface GetJqlSearchIssueResponse extends PostBulkFetchIssuesResponse {} - -export interface JiraSprint { - id: number, - name: string, - originBoardId: number -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/RuleEngine.ts b/playwright-tests/business-logic/types/RuleEngine.ts deleted file mode 100644 index 9c324204c..000000000 --- a/playwright-tests/business-logic/types/RuleEngine.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { BuiltInRules, builtInRules } from "@business-logic/rules/RuleEngineBuiltins"; -import LoggingUtils from "@impl/utils/LoggingUtils"; -import { ConsoleColor, ResultTypes } from "@business-logic/types/Enums"; - -//File Containing Rule Engine Implementation - -export type Rule = { - id: number; - name: string; - check: (obj: T) => boolean; - dependsOn?: number[]; -}; - -export class ValidationOptions { - public skipBuiltIns: boolean; - public exclude: number[]; - public throwOnError: boolean = true; - public errorsOnly: boolean = false; - - constructor(options: { - throwOnError?: boolean; - errorsOnly?: boolean; - skipBuiltIns?: boolean; - exclude?: number[]; - } = {}) { - this.throwOnError = options.throwOnError ?? true, this.errorsOnly = options.errorsOnly ?? true, this.skipBuiltIns = options.skipBuiltIns ?? false; - this.exclude = options.exclude ?? []; - } -} - -export class RuleEngine { - private rules: Rule[] = []; - private nextCustomRuleId = 1; - - static readonly BuiltInRuleIds: Record = {} as Record; - - constructor() { - this.addBuiltInRules(builtInRules as { id: BuiltInRules; name: string; check: (obj: T) => boolean; dependsOn?: BuiltInRules[]; }[]); - } - - private addBuiltInRules(builtInRules: { id: BuiltInRules; name: string; check: (obj: T) => boolean; dependsOn?: BuiltInRules[]; }[]): void { - builtInRules.forEach(rule => this.addRuleInternal(rule.name, rule.check, rule.id, rule.dependsOn)); - } - - private addRuleInternal(name: string, check: (obj: T) => boolean, builtInId: BuiltInRules, dependsOn?: BuiltInRules[]): number { - const id = builtInId; - const dependsOnIds = dependsOn?.map(dep => dep as number); - this.rules.push({ id, name, check, dependsOn: dependsOnIds }); - RuleEngine.BuiltInRuleIds[builtInId] = id; - return id; - } - - addRule(name: string, check: (obj: T) => boolean, options?: { dependsOn?: (number | BuiltInRules)[]; }): Rule { - if (this.nextCustomRuleId >= 1000) - throw new Error("Maximum number of custom rules (999) has been reached."); - - const id = this.nextCustomRuleId++; - const dependsOn = options?.dependsOn?.map(dep => typeof dep === "number" ? dep : RuleEngine.BuiltInRuleIds[dep]); - const rule: Rule = { id, name, check, dependsOn }; - this.rules.push(rule); - return rule; - } - - when(condition: (obj: T) => boolean): WhenClause { - return new WhenClause(this, condition); - } - - checkRuleById(id: number | BuiltInRules, obj: T): boolean { - const ruleId = typeof id === "number" ? id : RuleEngine.BuiltInRuleIds[id]; - const rule = this.rules.find(r => r.id === ruleId); - return rule ? rule.check(obj) : true; - } - - validate(obj: T): ValidationResult[] { - const sortedRules = this.sortRules(); - const results = new Map(); - const resultSummary: ValidationResult[] = []; - - sortedRules.forEach(rule => { - const dependenciesValid = rule.dependsOn ? rule.dependsOn.every(dep => results.get(dep)) : true; - const result = dependenciesValid && rule.check(obj); - results.set(rule.id, result); - - const resultType: ResultTypes = dependenciesValid ? result ? ResultTypes.Success : ResultTypes.Failure : ResultTypes.Skipped; - - resultSummary.push(ValidationResult.FromRule(rule.name, rule.id, resultType, `Rule: "${rule.name}". Result: ${ResultTypes[resultType]}`)); - }); - return resultSummary; - } - - private sortRules(): Rule[] { - const sortedRules: Rule[] = []; - const rulesMap = new Map(this.rules.map(rule => [rule.id, rule])); - - const visit = (rule: Rule, visited: Set, stack: Set) => { - if (stack.has(rule.id)) - throw new Error(`Circular dependency detected in rule: ${rule.name}!`); - - if (!visited.has(rule.id)) { - stack.add(rule.id); - if (rule.dependsOn) { - for (const dependency of rule.dependsOn) { - const dependencyRule = rulesMap.get(dependency); - if (dependencyRule) - visit(dependencyRule, visited, stack); - } - } - stack.delete(rule.id); - visited.add(rule.id); - sortedRules.push(rule); - } - }; - - const visited = new Set(); - for (const rule of this.rules) - visit(rule, visited, new Set()); - - return sortedRules; - } - - getRulesByName(name: string): Rule[] { - return this.rules.filter(rule => rule.name === name); - } - - getRulesByID(id: number): Rule[] { - return this.rules.filter(rule => rule.id === id); - } - - static PrintValidationResults(results: ValidationResult[], options: ValidationOptions = new ValidationOptions()) { - if (options.skipBuiltIns) - results = results.filter(x => x.ruleID < 1000); - - if (options.exclude) - results = results.filter(x => !options.exclude!.includes(x.ruleID)); - - if (options.errorsOnly) - results = results.filter(x => x.result == ResultTypes.Failure); - - if (results.length > 0) { - LoggingUtils.log("Rule Validation:", ConsoleColor.Blue); - results.forEach(x => LoggingUtils.log(` ${LoggingUtils.icon(x.result!)} Rule: [${x.ruleID}] "${x.ruleName}". Result: ${ResultTypes[x.result!]}`, x.result == ResultTypes.Success ? ConsoleColor.Green : ConsoleColor.Red)); - console.log(); - } - - if (options.throwOnError && results.filter(x => x.result != ResultTypes.Success).length > 0) - throw new Error("Rule Validation Errors"); - } -} - -export class WhenClause { - constructor(private ruleEngine: RuleEngine, private condition: (obj: T) => boolean) { } - - then(consequent: (obj: T) => boolean): DescriptionClause { - return new DescriptionClause(this.ruleEngine, (obj: T) => { - return !this.condition(obj) || consequent(obj); - }, []); - } -} - -export class DescriptionClause { - private dependencies: (number | BuiltInRules)[] = []; - - constructor(private ruleEngine: RuleEngine, private check: (obj: T) => boolean, dependencies: (number | BuiltInRules)[] = []) { - this.dependencies = dependencies; - } - - because(description: string): Rule { - return this.ruleEngine.addRule(description, this.check, { dependsOn: this.dependencies }); - } - - dependsOn(...dependencies: (number | BuiltInRules | (number | BuiltInRules)[])[]): DescriptionClause { - const flatDependencies = dependencies.flat(); - const tmp = (obj: T) => { - const dependenciesMet = flatDependencies.every(depId => this.ruleEngine.checkRuleById(depId, obj)); - return dependenciesMet && this.check(obj); - }; - return new DescriptionClause(this.ruleEngine, tmp, [...this.dependencies, ...flatDependencies]); - } -} -export class ValidationResult { - value: any; - ruleName: string; - ruleID: number; - error: string | null; - message: string; - result: ResultTypes | null; - - public static FromRule(ruleName: string, ruleID: number, result: ResultTypes, message: string) { - const retval = new ValidationResult(); - retval.ruleName = ruleName; - retval.ruleID = ruleID; - retval.result = result; - retval.message = message; - return retval; - } - - public static FromSuccess(value: any, message: string): ValidationResult { - const retval = new ValidationResult(); - retval.value = value; - retval.message = message; - retval.result = ResultTypes.Success; - return retval; - } - - public static FromFailure(error: string): ValidationResult { - const retval = new ValidationResult(); - retval.error = error; - retval.result = ResultTypes.Failure; - return retval; - } - - public static PrintValidationResults(results: ValidationResult[], options: ValidationOptions) { - const errors = results.filter(x => x.result == ResultTypes.Failure); - if (errors.length > 0) { - LoggingUtils.log("Type Validation Errors:", ConsoleColor.Red); - errors.forEach((message) => LoggingUtils.log(` ${LoggingUtils.icon(false)} ${message.error}`)); - console.log(); - } - - const successes = results.filter(x => x.result != ResultTypes.Failure); - - const suffix = "is valid."; - successes.sort((a, b) => { - const aa = a.message.endsWith(suffix); - const bb = b.message.endsWith(suffix); - - return Number(bb) - Number(aa); - }); - - if (!options.errorsOnly && successes.length > 0) { - LoggingUtils.log("Type Validation Messages:", ConsoleColor.Green); - successes.forEach((message) => LoggingUtils.log(` ${LoggingUtils.icon(true)} ${message.message}`)); - console.log(); - } - - if (options.throwOnError && errors.length > 0) - throw new Error("Validation Errors"); - } - - public static HasError(results: ValidationResult[]): boolean { - return results.filter(x => x.result == ResultTypes.Failure).length > 0; - } -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/Test.ts b/playwright-tests/business-logic/types/Test.ts deleted file mode 100644 index 80ebb6a5a..000000000 --- a/playwright-tests/business-logic/types/Test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { test as base } from "@playwright/test"; -import type { Page, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo as PlaywrightTestInfo } from "@playwright/test"; -import ITestCase from "@business-logic/types/ITestCase"; -import { RuleEngine, ValidationOptions } from "@business-logic/types/RuleEngine"; -import TestCase from "@business-logic/types/TestCase"; -import Soft from "@business-logic/validations/Soft"; -import FakerUtils from "@impl/utils/FakerUtils"; -import LoggingUtils from "@impl/utils/LoggingUtils"; - -// File containing test function implementations - -export type TestFunction = (args: PlaywrightTestArgs & PlaywrightTestOptions & PlaywrightWorkerArgs & PlaywrightWorkerOptions, testInfo: TestInfo) => void | Promise; -export type TestRunnerFunction = (page: Page, testInfo: TestInfo, /*testCase: TestCase*/) => void | Promise; - -export interface TestInfo extends PlaywrightTestInfo { - testCase: TestCase; -} - -export const test = base.extend<{ testInfo: TestInfo; }>({ - // Do not use the fixture because it is not extended, and will cause a circular reference error - // Use ({}, use, testInfo) not ({ testInfo }, use) - testInfo: async ({}, use, testInfo) => { - await use(testInfo as TestInfo); - } -}); - -export function addSmokeTagToRandomTest(testCases: ITestCase[]) { - const index = Math.floor(Math.random() * testCases.length); - testCases.at(index)?.tags.push("@smoke"); -} - -export function prepareTest(testData: ITestCase, testRunner: TestRunnerFunction, validationOptions: ValidationOptions, ruleEngine: RuleEngine): [string, object, TestFunction] { - const name = testData.name; - const attributes = { tag: TestCase.getTags(testData) }; - const testFunction: TestFunction = ({ page }, testInfo) => { - // Do not instantiate TestCase outside of this function, - // otherwise it will be instantiated several times for each test case - Soft.initialize(testInfo, page); - testInfo.testCase = new TestCase(testData, validationOptions, FakerUtils.getRandomTestID()); - const results = ruleEngine.validate(testInfo.testCase); - RuleEngine.PrintValidationResults(results, validationOptions); - console.log(LoggingUtils.logValidate(`TestID: ${testInfo.testCase.testID}`, true)); - return testRunner(page, testInfo, /*testInfo.testCase*/); - }; - return [name, attributes, testFunction]; -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/TestCase.ts b/playwright-tests/business-logic/types/TestCase.ts deleted file mode 100644 index ab45a6078..000000000 --- a/playwright-tests/business-logic/types/TestCase.ts +++ /dev/null @@ -1,186 +0,0 @@ -import PropertyUtils from "@impl/utils/PropertyUtils"; -import { formatTag } from "@impl/utils/TaggingUtils"; -import { Page } from "@playwright/test"; -import { TestInfo } from "@business-logic/types/Test"; -import { ConsoleColor } from "@business-logic/types/Enums"; -import FrameworkConfig from "@business-logic/types/FrameworkConfig"; -import { DisposableBase } from "@business-logic/types/IDisposable"; -import ITestCase from "@business-logic/types/ITestCase"; -import ITestPages from "./ITestPages"; -import { ValidationOptions, ValidationResult } from "@business-logic/types/RuleEngine"; -import Soft, { SoftError } from "@business-logic/validations/Soft"; -import Validations from "./Validations"; -import FakerUtils from "@impl/utils/FakerUtils"; -import { ITestData } from "./ITestData"; -import { HomePage } from "../../pages/HomePage"; -import { VehicleSelectionPage } from "../../pages/VehicleSelectionPage"; -import { VehicleDamagePage } from "../../pages/VehicleDamagePage"; -import { EstimatePage } from "../../pages/EstimatePage"; -import { VehicleLookupAddressPage } from "../../pages/VehicleLookupAddressPage"; -import { VehicleLookupLicensePage } from "../../pages/VehicleLookupLicensePage"; -import { VinLookupPage } from "../../pages/VinLookupPage"; -import { ServicePackagesPage } from "../../pages/ServicePackagesPage"; -import { LeadgenHomePage } from "../../pages/LeadgenHomePage"; -import { ServiceLocationPage } from "../../pages/ServiceLocationPage"; -import { SchedulePage } from "../../pages/SchedulePage"; -import { ContactDetailsPage } from "../../pages/ContactDetailsPage"; -import { PaymentMethodPage } from "../../pages/PaymentMethodPage"; -import { ZipLookupPage } from "../../pages/ZipLookupPage"; -import { OrderConfirmationPage } from "../../pages/OrderConfirmationPage"; -import { PartQuestionsPage } from "../../pages/PartQuestionPage"; -import VehiclePartQuestionsPage from "../../pages/VehiclePartsPage"; -import CapabilityQuestionsPage from "../../pages/CapabilityQuestionsPage"; -import MoldingQuestionsPage from "../../pages/MoldingQuestionsPage"; -import { InsuranceCompanyPage } from "../../pages/InsuranceCompanyPage"; -import { CCPolicyInfoPage } from "../../pages/CCPolicyInfoPage"; -import { DuplicateCheckPage } from "../../pages/DuplicateCheckPage"; -import { PolicyVehiclesPage } from "../../pages/PolicyVehiclesPage"; -import { PolicyInfoSubmittedPage } from "../../pages/PolicyInfoSubmittedPage"; -import RecalibrationInfoPage from "../../pages/RecalibrationInfoPage"; -import { CoverageStatementPage } from "../../pages/CoverageStatementPage"; -import { VerifyDetailsPage } from "../../pages/VerifyDetailsPage"; -import { EndorsementsPage } from "../../pages/EndorsementsPage"; -import { PolicyDriverPage } from "../../pages/PolicyDriverPage"; -import { ServiceZipPage } from "../../pages/ServiceZipPage"; - -// File for Test Case Class - -export default class TestCase extends DisposableBase implements ITestCase { - public static FrameworkConfig: FrameworkConfig = { - createResources: true, //process.env.FW_CREATE_RESOURCES! === "true", - destroyResources: true, // process.env.FW_DESTROY_RESOURCES! === "true", - maxAllotmentHours: Number(process.env.FW_MAX_ALLOTMENT_HOURS) - }; - - public static readonly Constants = class { - static readonly DISPOSE_HALTED: string = "FrameworkConfig is set to NOT destroy resources. Teardown halted!"; - static readonly CREATION_HALTED: string = "FrameworkConfig is set to NOT create resources. Preparation halted!"; - }; - - public readonly testID?: string; - public readonly name: string; - public readonly tags: string[]; - - public readonly testData: Partial; - - public readonly validations?: Validations; - public readonly tempData?: any[] = []; - - - public location: Location; - public alternateLocation?: Location; - - public pages: ITestPages; - - public constructor(data: ITestCase, validationOptions: ValidationOptions = new ValidationOptions(), testID: string) { - super(); - Object.assign(this, data); - this.testID = FakerUtils.getRandomTestID(); - - const validationResults: ValidationResult[] = []; - - this.name = PropertyUtils.getValue(data, TestCase.name, validationResults, { isRequired: true }, x => x.name); - this.tags = PropertyUtils.getValue(data, TestCase.name, validationResults, { isRequired: true }, x => x.tags); - this.validations = PropertyUtils.getValue(data, TestCase.name, validationResults, { isRequired: false }, x => x.validations); - - // if (PropertyUtils.hasProperty(data, TestCase.name, validationResults, { isRequired: false }, x => x.oldTransactions)) - // this.oldTransactions = data.oldTransactions.map((item: any) => new TransactionData(item, validationResults, this.testID)); - - // if (PropertyUtils.hasProperty(data, TestCase.name, validationResults, { isRequired: true }, x => x.transaction)) - // this.transaction = new TransactionData(data.transaction, validationResults, this.testID); - - ValidationResult.PrintValidationResults(validationResults, validationOptions); - } - - public static getTags(testCase: ITestCase): string[] { - const retval = [ - ...testCase.tags, - formatTag(testCase.name), - ]; - - return retval; - } - - public static async afterEachMethod(page: Page, testInfo: TestInfo) { - const originalStatus = testInfo.status; - - if (Soft.hasFailedAssertions()) - testInfo.status = "failed"; - - for (const a of Soft.getFailedAssertions()) - testInfo.errors.push(new SoftError(a)); - - // NOTE: This try catch is here because the tests when locally, frequently - // fail tests on screenshot, which we do not want, is it make it - // harder to parse any other real errors we do care about. T.S. 9.5.2024 - try { - await testInfo.attach("End of Test Screenshot", { - body: await page.screenshot({ fullPage: true }), - contentType: 'image/png' - }); - } catch(error) { - console.error(error); - } - - - if (testInfo.testCase) - await testInfo.testCase.disposeAll(); - - const seconds: string = String(testInfo.duration / 1000); - const minutes: string = (testInfo.duration / 1000 / 60).toFixed(2); - const validationErrors: string = Soft.hasFailedAssertions() ? ` with ${Soft.getFailureCount()} validation errors` : ""; - - if (originalStatus == "failed") - console.log(`${ConsoleColor.Red}Test failed after ${seconds} seconds, or roughly ${minutes} minutes${validationErrors}.${ConsoleColor.Reset}`); - else { - if (testInfo.status == "passed") - console.log(`${ConsoleColor.Green}Test finished successfully in ${seconds} seconds, or roughly ${minutes} minutes.${ConsoleColor.Reset}`); - else - console.log(`${ConsoleColor.Orange}Test finished in ${seconds} seconds, or roughly ${minutes} minutes${validationErrors}.${ConsoleColor.Reset}`); - } - console.log(page.url()); - } - - public async setup(): Promise { - //Setup for Test case - } - - public setupPages(page: Page): void { - this.pages = { - capabilityQuestionsPage: new CapabilityQuestionsPage(page), - ccPolicyInfoPage: new CCPolicyInfoPage(page), - contactDetailsPage: new ContactDetailsPage(page), - coverageStatementPage: new CoverageStatementPage(page), - duplicateCheckPage: new DuplicateCheckPage(page), - estimatePage: new EstimatePage(page), - homePage: new HomePage(page), - insuranceCompanyPage: new InsuranceCompanyPage(page), - leadgenHomePage: new LeadgenHomePage(page), - moldingQuestionsPage: new MoldingQuestionsPage(page), - orderConfirmationPage: new OrderConfirmationPage(page), - partQuestionsPage: new PartQuestionsPage(page), - paymentMethodPage: new PaymentMethodPage(page), - policyInfoSubmittedPage: new PolicyInfoSubmittedPage(page), - policyVehiclesPage: new PolicyVehiclesPage(page), - recalibrationInfoPage: new RecalibrationInfoPage(page), - schedulePage: new SchedulePage(page), - serviceLocationPage: new ServiceLocationPage(page), - servicePackagesPage: new ServicePackagesPage(page), - serviceZipPage: new ServiceZipPage(page), - vehicleDamagePage: new VehicleDamagePage(page), - vehicleLookupAddressPage: new VehicleLookupAddressPage(page), - vehicleLookupLicensePage: new VehicleLookupLicensePage(page), - vehiclePartsPage: new VehiclePartQuestionsPage(page), - vehicleSelectionPage: new VehicleSelectionPage(page), - verifyDetailsPage: new VerifyDetailsPage(page), - vinLookupPage: new VinLookupPage(page), - zipLookupPage: new ZipLookupPage(page), - endorsementsPage: new EndorsementsPage(page), - policyDriverPage: new PolicyDriverPage(page) - }; - } - - protected async dispose(): Promise { - // Tear down for test case - } -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/TestSuccessAlert.ts b/playwright-tests/business-logic/types/TestSuccessAlert.ts deleted file mode 100644 index fe3d6b941..000000000 --- a/playwright-tests/business-logic/types/TestSuccessAlert.ts +++ /dev/null @@ -1,6 +0,0 @@ -export default class TestSuccessAlert extends Error { - constructor(message: string) { - super(message); - this.name = "TestSuccessAlert"; - } -} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/Validations.ts b/playwright-tests/business-logic/types/Validations.ts deleted file mode 100644 index f82c7fbaf..000000000 --- a/playwright-tests/business-logic/types/Validations.ts +++ /dev/null @@ -1,13 +0,0 @@ -import PropertyUtils from "@impl/utils/PropertyUtils"; -import IValidations from "./IValidations"; -import { ValidationResult } from "./RuleEngine"; - -// File containing validation class - -export default class Validations implements IValidations { - public readonly exampleValue: boolean; - - public constructor(json: any, validationResults: ValidationResult[]) { - this.exampleValue = PropertyUtils.getValue(json, Validations.name, validationResults, { isRequired: true }, x => x.exampleValue); - } -} diff --git a/playwright-tests/business-logic/validations/Soft.ts b/playwright-tests/business-logic/validations/Soft.ts deleted file mode 100644 index 69fbfb734..000000000 --- a/playwright-tests/business-logic/validations/Soft.ts +++ /dev/null @@ -1,179 +0,0 @@ -import LoggingUtils from '@impl/utils/LoggingUtils'; -import { Page } from '@playwright/test'; -import { TestInfo } from '@business-logic/types/Test'; -import { TestInfoError } from "@playwright/test"; -import { DateTime } from 'luxon'; -import { expect as pw_expect } from '@playwright/test'; - -export default class Soft { - private static _instance: Soft | null = null; - private testInfo: TestInfo; - private page: Page; - private failedAssertions: string[] = []; - private errorCounter: number = 0; - private errorsOnly: boolean = false; - - private constructor(testInfo: TestInfo, page: Page) { - this.testInfo = testInfo; - this.page = page; - } - - public static initialize(testInfo: TestInfo, page: Page): void { - Soft._instance = new Soft(testInfo, page); - } - - public static setOptions(options: { errorsOnly: boolean }): void { - Soft.getInstance().errorsOnly = options.errorsOnly; - } - - public static getOptions(): { errorsOnly: boolean } { - return { errorsOnly: Soft.getInstance().errorsOnly }; - } - - private static getInstance(): Soft { - if (!Soft._instance) - throw new Error("Soft is not initialized. Call Soft.initialize(testInfo, page) first!"); - return Soft._instance; - } - - public async handleAssertion( - matcherFull: string, - matcherDisplay: string, - matcherFunction: () => Promise, - reason?: string): Promise { - reason = reason ? reason : '' - const reasonText = reason ? `'${reason}' ` : ''; - try { - await matcherFunction(); - if (!this.errorsOnly) - console.log(LoggingUtils.logValidate(`Validation ${reasonText}passed: ${matcherDisplay}!`, true)); - } catch (error) { - console.log(LoggingUtils.logValidate(`Validation ${reasonText}failed: ${matcherDisplay}!`, false)); - //const errorMessage = error instanceof Error ? error.message : String(error); - this.failedAssertions.push(`\n${++this.errorCounter}_Validation ${reasonText}failed:\n${LoggingUtils.replaceEmptyLinesWithMiddleDot(matcherFull)}!\n${error.stack}\n`); - // NOTE: I find it more helpful for the stack trace to be included here, so we know which line the validation is failing - try { - const screenshot: Buffer = await this.page.screenshot({ fullPage: true }); - const name: string = LoggingUtils.sanitizeFileName(`${this.errorCounter}_Validation_${reason}${DateTime.now().valueOf()}`); - await this.testInfo.attach(name, { - body: screenshot, - contentType: 'image/png' - }); - } catch(err){ - // ohwell - console.error(error) - } - - } - } - - public static expect(value: any, reason?: string): ExpectationChain { - return new ExpectationChain(value, Soft.getInstance(), reason); - } - - public static getFailedAssertions(): string[] { - return Soft.getInstance().failedAssertions; - } - - public static hasFailedAssertions(): boolean { - return Soft.getInstance().failedAssertions.length > 0; - } - - public static getFailureCount(): number { - return Soft.getInstance().failedAssertions.length; - } - - public static clearFailedAssertions(): void { - Soft.getInstance().failedAssertions = []; - } -} - -export class SoftError implements TestInfoError { - public readonly message?: string | undefined; - constructor(msg: string) { - this.message = msg; - } -} - -export class ExpectationChain { - constructor(private value: any, private soft: Soft, private reason?: string) { } - - private formatValue(value: any): string { - return LoggingUtils.truncateString(value); - } - - public async toBe(expected: any): Promise { - await this.soft.handleAssertion( - `expect(${this.value}).toBe(${expected})`, - `expect(${this.formatValue(this.value)}).toBe(${this.formatValue(expected)})`, - async () => await pw_expect(this.value).toBe(expected), - this.reason - ); - return this; - } - - public async toEqual(expected: any): Promise { - await this.soft.handleAssertion( - `expect(${JSON.stringify(this.value)}).toEqual(${expected})`, - `expect(${this.formatValue(JSON.stringify(this.value))}).toEqual(${this.formatValue(expected)})`, - async () => await pw_expect(this.value).toEqual(expected), - this.reason - ); - return this; - } - - public async toContain(expected: any): Promise { - await this.soft.handleAssertion( - `expect(${this.value}).toContain(${expected})`, - `expect(${this.formatValue(this.value)}).toContain(${this.formatValue(expected)})`, - async () => await pw_expect(this.value).toContain(expected), - this.reason - ); - return this; - } - - public async toHaveText(expected: string): Promise { - await this.soft.handleAssertion( - `expect(${this.value}).toHaveText(${expected})`, - `expect(${this.formatValue(this.value)}).toHaveText(${this.formatValue(expected)})`, - async () => { - if (typeof this.value.textContent !== 'function') { - throw new Error('value does not have a textContent method'); - } - const text = await this.value.textContent(); - await pw_expect(text).toHaveText(expected); - }, this.reason - ); - return this; - } - - public async toBeGreaterThan(expected: number): Promise { - await this.soft.handleAssertion( - `expect(${this.value}).toBeGreaterThan(${expected})`, - `expect(${this.formatValue(this.value)}).toBeGreaterThan(${this.formatValue(expected)})`, - async () => await pw_expect(this.value).toBeGreaterThan(expected), - this.reason - ); - return this; - } - - public async toBeTruthy(): Promise { - await this.soft.handleAssertion( - `expect(${this.value}).toBeTruthy`, - `expect(${this.formatValue(this.value)}).toBeTruthy`, - async () => await pw_expect(this.value).toBeTruthy(), - this.reason - ); - return this; - } - - public async toBeFalsy(): Promise { - await this.soft.handleAssertion( - `expect(${this.value}).toBeFalsy`, - `expect(${this.formatValue(this.value)}).toBeFalsy`, - async () => await pw_expect(this.value).toBeFalsy(), - this.reason - ); - return this; - } -} \ No newline at end of file diff --git a/playwright-tests/framework/TestData.ts b/playwright-tests/framework/TestData.ts new file mode 100644 index 000000000..8f00bb276 --- /dev/null +++ b/playwright-tests/framework/TestData.ts @@ -0,0 +1,7 @@ +import { ITestData as base } from 'safelite-playwright-core' +import { PaymentMethod } from './localTypes/Enums' + +export interface ITestData extends base { + // Put any project-specific data here. Anything useful to other Safelite projects should be submitted as a pull request to safelite-playwright-core. + paymentMethod: PaymentMethod +} \ No newline at end of file diff --git a/playwright-tests/framework/TestPages.ts b/playwright-tests/framework/TestPages.ts new file mode 100644 index 000000000..cfc7940bd --- /dev/null +++ b/playwright-tests/framework/TestPages.ts @@ -0,0 +1,101 @@ +import { Page } from "@playwright/test"; +import { type TestPagesFactory } from 'safelite-playwright-core' +import { HomePage } from "../pages/HomePage" +import { LeadgenHomePage } from "../pages/LeadgenHomePage" +import { ServicePackagesPage } from "../pages/ServicePackagesPage" +import { VehicleDamagePage } from "../pages/VehicleDamagePage" +import { VehicleLookupAddressPage } from "../pages/VehicleLookupAddressPage" +import { VehicleLookupLicensePage } from "../pages/VehicleLookupLicensePage" +import { EstimatePage } from "../pages/EstimatePage" +import { VehicleSelectionPage } from "../pages/VehicleSelectionPage" +import { VinLookupPage } from "../pages/VinLookupPage" +import { ServiceLocationPage } from "../pages/ServiceLocationPage" +import { SchedulePage } from "../pages/SchedulePage" +import { ContactDetailsPage } from "../pages/ContactDetailsPage" +import { PaymentMethodPage } from "../pages/PaymentMethodPage" +import { ZipLookupPage } from "../pages/ZipLookupPage" +import { OrderConfirmationPage } from "../pages/OrderConfirmationPage" +import { PartQuestionsPage } from "../pages/PartQuestionPage" +import VehiclePartQuestionsPage from "../pages/VehiclePartsPage" +import CapabilityQuestionsPage from "../pages/CapabilityQuestionsPage" +import MoldingQuestionsPage from "../pages/MoldingQuestionsPage" +import { InsuranceCompanyPage } from "../pages/InsuranceCompanyPage" +import { CCPolicyInfoPage } from "../pages/CCPolicyInfoPage" +import { DuplicateCheckPage } from "../pages/DuplicateCheckPage" +import { PolicyVehiclesPage } from "../pages/PolicyVehiclesPage" +import { PolicyInfoSubmittedPage } from "../pages/PolicyInfoSubmittedPage" +import RecalibrationInfoPage from "../pages/RecalibrationInfoPage" +import { CoverageStatementPage } from "../pages/CoverageStatementPage" +import { VerifyDetailsPage } from "../pages/VerifyDetailsPage" +import { EndorsementsPage } from "../pages/EndorsementsPage" +import { PolicyDriverPage } from "../pages/PolicyDriverPage" +import { ServiceZipPage } from "../pages/ServiceZipPage" + +export interface ITestPages { + capabilityQuestionsPage: CapabilityQuestionsPage, + ccPolicyInfoPage: CCPolicyInfoPage, + contactDetailsPage: ContactDetailsPage, + coverageStatementPage: CoverageStatementPage, + duplicateCheckPage: DuplicateCheckPage, + estimatePage: EstimatePage, + homePage: HomePage, + insuranceCompanyPage: InsuranceCompanyPage, + leadgenHomePage: LeadgenHomePage, + moldingQuestionsPage: MoldingQuestionsPage, + orderConfirmationPage: OrderConfirmationPage, + partQuestionsPage: PartQuestionsPage, + paymentMethodPage: PaymentMethodPage, + policyInfoSubmittedPage: PolicyInfoSubmittedPage, + policyVehiclesPage: PolicyVehiclesPage, + recalibrationInfoPage: RecalibrationInfoPage, + schedulePage: SchedulePage, + serviceLocationPage: ServiceLocationPage, + servicePackagesPage: ServicePackagesPage, + serviceZipPage: ServiceZipPage, + vehicleDamagePage: VehicleDamagePage, + vehicleLookupAddressPage: VehicleLookupAddressPage, + vehicleLookupLicensePage: VehicleLookupLicensePage, + vehiclePartsPage: VehiclePartQuestionsPage, + vehicleSelectionPage: VehicleSelectionPage, + verifyDetailsPage: VerifyDetailsPage, + vinLookupPage: VinLookupPage, + zipLookupPage: ZipLookupPage, + endorsementsPage: EndorsementsPage, + policyDriverPage: PolicyDriverPage, +} + +export const createTestPages: TestPagesFactory = (page: Page) => { + const pages: ITestPages = { + capabilityQuestionsPage: new CapabilityQuestionsPage(page), + ccPolicyInfoPage: new CCPolicyInfoPage(page), + contactDetailsPage: new ContactDetailsPage(page), + coverageStatementPage: new CoverageStatementPage(page), + duplicateCheckPage: new DuplicateCheckPage(page), + estimatePage: new EstimatePage(page), + homePage: new HomePage(page), + insuranceCompanyPage: new InsuranceCompanyPage(page), + leadgenHomePage: new LeadgenHomePage(page), + moldingQuestionsPage: new MoldingQuestionsPage(page), + orderConfirmationPage: new OrderConfirmationPage(page), + partQuestionsPage: new PartQuestionsPage(page), + paymentMethodPage: new PaymentMethodPage(page), + policyInfoSubmittedPage: new PolicyInfoSubmittedPage(page), + policyVehiclesPage: new PolicyVehiclesPage(page), + recalibrationInfoPage: new RecalibrationInfoPage(page), + schedulePage: new SchedulePage(page), + serviceLocationPage: new ServiceLocationPage(page), + servicePackagesPage: new ServicePackagesPage(page), + serviceZipPage: new ServiceZipPage(page), + vehicleDamagePage: new VehicleDamagePage(page), + vehicleLookupAddressPage: new VehicleLookupAddressPage(page), + vehicleLookupLicensePage: new VehicleLookupLicensePage(page), + vehiclePartsPage: new VehiclePartQuestionsPage(page), + vehicleSelectionPage: new VehicleSelectionPage(page), + verifyDetailsPage: new VerifyDetailsPage(page), + vinLookupPage: new VinLookupPage(page), + zipLookupPage: new ZipLookupPage(page), + endorsementsPage: new EndorsementsPage(page), + policyDriverPage: new PolicyDriverPage(page) + }; + return pages; +} \ No newline at end of file diff --git a/playwright-tests/framework/Typedefs.ts b/playwright-tests/framework/Typedefs.ts new file mode 100644 index 000000000..8584c9984 --- /dev/null +++ b/playwright-tests/framework/Typedefs.ts @@ -0,0 +1,12 @@ +import { getTestObject as getTestObject_T, prepareTest as prepareTest_T, RuleEngine as RuleEngine_T, TestCase as TestCase_T, TestInfo as TestInfo_T, ITestCase as ITestCase_T} from 'safelite-playwright-core' +import { ITestPages } from './TestPages' +import { ITestData } from './TestData' + +export const getTestObject = getTestObject_T; +export const prepareTest = prepareTest_T; + +export const RuleEngine = RuleEngine_T>; +export class TestCase extends TestCase_T {}; +export type TestInfo = TestInfo_T; + +export type ITestCase = ITestCase_T; diff --git a/playwright-tests/framework/localTypes/Enums.ts b/playwright-tests/framework/localTypes/Enums.ts new file mode 100644 index 000000000..067011f5e --- /dev/null +++ b/playwright-tests/framework/localTypes/Enums.ts @@ -0,0 +1,26 @@ + +export enum PaymentMethod { + Insurance = 'Insurance', + SelfPay = 'SelfPay' +} + +export enum ProgressBarPercentages { + VehicleSelectionPage = '4%', + VehicleDamagePage = '16%', + EstimatePage = '28%', + ServiceZipPage = '32%', + VehicleLookupAddressPage = '32%', + VehicleLookupLicensePage = '32%', + VinLookupPage = '32%', + PartQuestionsPage = '40%', + MoldingQuestionsPage = '40%', + CapabilityQuestionsPage = '40%', + VehiclePartsPage = '40%', + ServicePackagePage = '48%', + InsuranceCompanyPage = '52%', + ServiceLocationPage = '60%', + SchedulePage = '72%', + ContactDetailsPage = '84%', + PaymentMethodPage = '92%', + OrderConfirmationPage = '100%' +} \ No newline at end of file diff --git a/playwright-tests/business-logic/types/Step.ts b/playwright-tests/framework/localTypes/Step.ts similarity index 88% rename from playwright-tests/business-logic/types/Step.ts rename to playwright-tests/framework/localTypes/Step.ts index 693e34da2..ee62fd152 100644 --- a/playwright-tests/business-logic/types/Step.ts +++ b/playwright-tests/framework/localTypes/Step.ts @@ -1,4 +1,6 @@ -import { test } from '@business-logic/types/Test'; +import { getTestObject } from "framework/Typedefs"; + +const test = getTestObject() export type Context = { kind: string; diff --git a/playwright-tests/impl/API/ApiResponseInterceptUtil.ts b/playwright-tests/impl/API/ApiResponseInterceptUtil.ts deleted file mode 100644 index 77810a781..000000000 --- a/playwright-tests/impl/API/ApiResponseInterceptUtil.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { IPartsOrQuestionsResponse } from "@business-logic/types/DigitalAPI"; -import { ITestData } from "@business-logic/types/ITestData"; -import { expect, Response } from "@playwright/test"; - -export default class ApiResponseInterceptUtil { - readonly testData: Partial; - - constructor(testData: Partial) { - this.testData = testData; - - // Bind callback functions to the class instance so 'this' is usable within a callback - this.handleInterceptResponse = this.handleInterceptResponse.bind(this); - this.handlePartsOrQuestionsResponse = this.handlePartsOrQuestionsResponse.bind(this); - } - - async handleInterceptResponse(response: Response) { - if (!response.url().includes('safelite.io')) { - return; - } - - const urlPath = response.url().split('safelite.io')[1]; // get api path - - switch(urlPath) { - case '/parts/api/v1/parts/parts-or-questions': - await this.handlePartsOrQuestionsResponse(response); - break; - //TODO: add validation for other urls in the API - default: - break; - } - if (response.url().endsWith('/parts/parts-or-questions') && response.status() === 200) { - - } - } - - async handlePartsOrQuestionsResponse(response: Response) { - if (this.testData.hasOemEndorsement) { - const partsRes = (await response.json()) as IPartsOrQuestionsResponse; - for ( const partOrQuestion of partsRes.partsOrQuestions) { - for (const part of partOrQuestion.parts) { - expect.soft(part.partNumber.endsWith('OEM'), - `handlePartsOrQuestionsResponse>> OEM endorsement was expected, but "${part.partType}" with part number "${part.partNumber}" is not OEM.` - ).toEqual(true); - } - } - } - } -} \ No newline at end of file diff --git a/playwright-tests/impl/API/JiraApiUtil.ts b/playwright-tests/impl/API/JiraApiUtil.ts deleted file mode 100644 index 41299aa5e..000000000 --- a/playwright-tests/impl/API/JiraApiUtil.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { PostBulkFetchIssuesRequestBody, PostBulkFetchIssuesResponse, GetIssueResponse, GetIssueTransitionsResponse, GetIssueTypesResponse, PostAddCommentResponse, PostBulkCreateIssueRequestBody, PostBulkCreateIssueResponse, PostCreateIssueRequestBody, PostCreateIssueResponse, PostTransitionIssueRequestBody, PutEditIssueRequestBody, PostBulkTransitionIssuesRequestBody, GetSprintResponse, GetJqlSearchIssueParams, GetJqlSearchIssueResponse } from "@business-logic/types/JiraApi"; -import axios, { AxiosInstance } from "axios"; -import axiosRetry from "axios-retry"; -import FormData from 'form-data'; -import path from "path"; -import fs from 'fs'; - -const jiraUrl = process.env.JIRA_SERVER!; -const jiraUsername = process.env.JIRA_USERNAME!; -const jiraApiKey = process.env.JIRA_API_KEY!; -const boardId = process.env.JIRA_BOARD_ID!; -const encodedAuthKey = Buffer.from(`${jiraUsername}:${jiraApiKey}`).toString('base64'); - -export default class JiraApiUtil { - readonly baseUrl: string; - readonly issueUrl: string; - readonly bulkIssueCreateUrl: string; - readonly bulkIssueFetchUrl: string; - readonly bulkTransitionIssuesUrl: string; - readonly getCurrentSprintUrl: string; - readonly getJqlSearchIssueUrl: string; - - readonly axiosClient: AxiosInstance; - - constructor() { - this.baseUrl = jiraUrl; - this.issueUrl = `${this.baseUrl}/rest/api/3/issue`; - this.bulkIssueCreateUrl = `${this.issueUrl}/bulk`; - this.bulkIssueFetchUrl = `${this.issueUrl}/bulkfetch`; - this.bulkTransitionIssuesUrl = `${this.baseUrl}/rest/api/3/bulk/issues/transition`; - this.getCurrentSprintUrl = `${this.baseUrl}/rest/agile/1.0/board/${boardId}/sprint?state=active`; - this.getJqlSearchIssueUrl = `${this.baseUrl}/rest/api/3/search/jql`; - this.axiosClient = axios.create(); - // interceptor to log error message from api - this.axiosClient.interceptors.response.use( - response => response, - error => { - console.error('Axios Error:', error?.response?.data || error.message); - return Promise.reject(error); - } - ); - // Set up retries if requests are made too quickly - axiosRetry(this.axiosClient, { - retries: 4, - retryDelay: (retryCount) => { return Math.pow(2, retryCount) * 1000; }, // Exponential backoff - retryCondition: (error) => { return error.response?.status === 429 } // If rate-limit error - }); - } - - getIssue(issueKey: string) { - const url = `${this.issueUrl}/${issueKey}`; - return this.axiosClient.get(url, { - headers: { - Authorization: `Basic ${encodedAuthKey}`, - Accept: 'application/json' - } - }); - } - - async getCurrentSprint() { - const res = await this.axiosClient.get(this.getCurrentSprintUrl, { - headers: { - Authorization: `Basic ${encodedAuthKey}`, - Accept: 'application/json' - } - }); - const currentSprint = res.data.values.filter(sprint => { - return `${sprint.originBoardId}` === boardId; - }); - if (currentSprint.length === 1) { - return currentSprint[0]; - } else { - console.error(`JiraApiUtil >> Multiple active sprints found for board ${boardId}`); - } - } - - getJqlSearchIssue(params: GetJqlSearchIssueParams) { - return this.axiosClient.get(this.getJqlSearchIssueUrl, { - params: params, - headers: { - Authorization: `Basic ${encodedAuthKey}`, - Accept: 'application/json' - } - }) - } - - postBulkFetchIssues(requestBody: PostBulkFetchIssuesRequestBody) { - return this.axiosClient.post(this.bulkIssueFetchUrl, requestBody, { - headers: { - Authorization: `Basic ${encodedAuthKey}`, - 'Accept': 'application/json', - 'Content-Type': 'application/json' - } - }); - } - - getIssueTransitions(issueKey: string) { - const url = `${this.issueUrl}/${issueKey}/transitions` - return this.axiosClient.get(url, { - headers: { - Authorization: `Basic ${encodedAuthKey}`, - Accept: 'application/json' - } - }); - } - - getIssueTypes(projectKey: string) { - const url = `${this.baseUrl}/rest/api/3/issue/createmeta/${projectKey}/issuetypes`; - return this.axiosClient.get(url, { - headers: { - Authorization: `Basic ${encodedAuthKey}`, - Accept: 'application/json' - } - }); - } - - postAddComment(issueKey: string, commentBody: PostAddCommentResponse) { - const url = `${this.issueUrl}/${issueKey}/comment`; - return this.axiosClient.post(url, commentBody, { - headers: { - Authorization: `Basic ${encodedAuthKey}`, - 'Accept': 'application/json', - 'Content-Type': 'application/json' - } - }); - } - - postTransitionIssue(issueKey: string, requestBody: PostTransitionIssueRequestBody) { - const transitionUrl = `${this.issueUrl}/${issueKey}/transitions` - return this.axiosClient.post(transitionUrl, requestBody, { - headers: { - Authorization: `Basic ${encodedAuthKey}`, - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - }); - } - - putEditIssue(issueKey: string, requestBody: PutEditIssueRequestBody) { - const editIssueUrl = `${this.issueUrl}/${issueKey}` - return this.axiosClient.put(editIssueUrl, requestBody, { - headers: { - Authorization: `Basic ${encodedAuthKey}`, - 'Accept': 'application/json', - 'Content-Type': 'application/json' - } - }); - } - - postBulkTransitionIssues(requestBody: PostBulkTransitionIssuesRequestBody) { - return this.axiosClient.post(this.bulkTransitionIssuesUrl, requestBody, { - headers: { - Authorization: `Basic ${encodedAuthKey}`, - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - }); - } - - postCreateIssue(requestBody: PostCreateIssueRequestBody) { - return this.axiosClient.post(this.issueUrl, requestBody, { - headers: { - Authorization: `Basic ${encodedAuthKey}`, - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - }); - } - - postBulkCreateIssue(requestBody: PostBulkCreateIssueRequestBody) { - return this.axiosClient.post(this.bulkIssueCreateUrl, requestBody, { - headers: { - Authorization: `Basic ${encodedAuthKey}`, - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - }); - } - - postUploadAttachment(issueKey: string, filePath: string) { - const url = `${this.baseUrl}/rest/api/3/issue/${issueKey}/attachments` - const form = new FormData(); - const fileName = path.basename(filePath); - - form.append('file', fs.createReadStream(filePath), fileName); - return this.axiosClient.post(url, form, { - headers: { - Authorization: `Basic ${encodedAuthKey}`, - 'X-Atlassian-Token': 'no-check', - ...form.getHeaders() - } - }); - } -} \ No newline at end of file diff --git a/playwright-tests/impl/reporter/JiraWritebackReporter.ts b/playwright-tests/impl/reporter/JiraWritebackReporter.ts deleted file mode 100644 index 62b2bdebd..000000000 --- a/playwright-tests/impl/reporter/JiraWritebackReporter.ts +++ /dev/null @@ -1,449 +0,0 @@ -import JiraApiUtil from "@impl/API/JiraApiUtil"; -import type { FullConfig, FullResult, Reporter, Suite, TestCase, TestError, TestResult } from "@playwright/test/reporter"; -import { formatDate, formatDateForFilename } from "@impl/utils/DateUtils"; -import { GetIssueResponse, JiraIssue, JiraIssueFields } from "@business-logic/types/JiraApi"; -import OrtoniReport, { OrtoniReportConfig } from "ortoni-report"; - -let jiraCardNumber = process.env.JIRA_CARD_NUMBER || ''; -const isRegressionRun = process.env.IS_REGRESSION === 'true'? true: false; -const jiraProjectKey = process.env.JIRA_PROJECT_KEY!; -const jiraEpicKey = process.env.JIRA_EPIC_KEY!; -const passTransitionId = '111'; -const failTransitionId = '101'; -const inTestTransitionId = '271'; -const currentDate = formatDateForFilename(new Date()); - -// Ortoni config -const reportName = `ortoni_report_${currentDate}.html`; -const reportConfig: OrtoniReportConfig = { - port: 1994, - open: "never", - folderPath: "ortoni-report", - filename: reportName, - logo: 'playwright-tests/business-logic/data/logo.png', - title: "Test Report", - showProject: false, - projectName: "FMG-Nextgen-Playwright-Report", - testType: `E2E- Environment: ${process.env.NODE_ENV} `, - preferredTheme: "light", - base64Image: true, -}; - -export default class JiraWritebackReporter implements Reporter { - readonly jiraApiUtil: JiraApiUtil = new JiraApiUtil(); - readonly ortoniReport: OrtoniReport = new OrtoniReport(reportConfig); - readonly loadIssueCalls: (() => void)[] = []; // Calls to loadIssue must be deferred because they depend on information from the API. - readonly issuesToPass: string[] = []; // Issues to transition to "Pass". - readonly issuesToFail: string[] = []; // Issues to transition to "Fail". - readonly issuesToCreate: JiraIssue[] = []; // Issues to be batch created. - existingSubtasks: JiraIssue[] = []; // Array to hold existing subtasks of the dev card. - testCaseTypeId: string|undefined = undefined; // ID of the test case subtask type in Jira. Will be filled by API call. - bugTypeId:string|undefined = undefined; // ID of the bug subtask type. - userStoryTypeId:string|undefined = undefined; - parentCard: GetIssueResponse | undefined = undefined; // Variable to hold the parent card. Will be filled by API call. - - // Will need this if we want to move ortoni report upload into this reporter. - // readonly ortoniReport = new OrtoniReport(reportConfig); - - /** - * This function loads the IDs for the Jira Issue Types we use. - * - */ - async loadJiraIssueTypes() { - console.log(`JiraWritebackReporter >> Loading Jira Issue Types for project '${jiraProjectKey}'...`); - const issueTypesRes = await this.jiraApiUtil.getIssueTypes(jiraProjectKey); - const issueTypes = issueTypesRes.data; - this.testCaseTypeId = issueTypes.issueTypes.find(issueType => { - return issueType.subtask === true && issueType.name === 'Test Case Sub-task' - })?.id; - this.bugTypeId = issueTypes.issueTypes.find(issueType => { - return issueType.subtask === true && issueType.name === 'Bug Sub-task' - })?.id; - this.userStoryTypeId = issueTypes.issueTypes.find(issueType => { - return issueType.name === 'Story'; - })?.id; - console.log('JiraWritebackReporter >> Loaded issue types.'); - } - - /** - * This function generates a test subtask based on the test results we pass in. - * @param test TestCase from onTestEnd() - * @param result TestResult from onTestEnd() - * @returns Jira Test Subtask based on test result. - */ - getCreateTestSubtask(test: TestCase, result: TestResult) { - if (result.status === 'skipped') { - return undefined; - } - const testStepTitles = result.steps.map(step => { - return `-\t${step.title}`; - }).join('\n'); - const allErrors = result.errors.map(value => { - return value.message - }).join('\n'); - - const description = `Most recent test status: ${result.status}.\nDuration: ${result.duration/1000} seconds.\nErrors:\n${allErrors}` - const testSubtaskBody: JiraIssueFields = { - summary: test.title, - description: { - content: [ - { - "content": [ - { - "text": description, - "type": "text" - } - ], - "type": "paragraph" - } - ], - "type": "doc", - "version": 1 - }, - project: { - key: jiraProjectKey - }, - issuetype: { - id: this.testCaseTypeId! - }, - parent: { - key: jiraCardNumber - }, - customfield_14857: { - type: 'doc', - version: 1, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: testStepTitles - } - ] - } - ] - } - }; - return testSubtaskBody; - } - - /** - * This function generates a bug subtask based on the test results we pass in. - * @param test TestCase from onTestEnd() - * @param result TestResult from onTestEnd() - * @returns Jira Bug Subtask based on test result. - */ - getCreateBug(test: TestCase, result: TestResult) { - if (result.status === 'passed' || result.status === 'skipped') { - return undefined; - } - const allErrors = result.errors.map(value => { - return value.message - }).join('\n'); - - const bug: JiraIssueFields = { - summary: `TEST FAILED ${formatDate(new Date())}: ${test.title}`, - description: { - content: [ - { - "content": [ - { - "text": allErrors, - "type": "text" - } - ], - "type": "paragraph" - } - ], - "type": "doc", - "version": 1 - }, - project: { - key: jiraProjectKey - }, - issuetype: { - id: this.bugTypeId! - }, - parent: { - key: jiraCardNumber - } - }; - return bug; - } - - /** - * This function gives us the correct transition for a test subtask based on this test result. - * @param result TestResult from onTestEnd() - * @returns Correct transition to pass to the Jira API. - */ - getSubtaskTransition(result: TestResult): { id: string } | undefined { - if (result.status === 'skipped') { - return undefined; - } - - if (result.status === 'passed') { - return { - id: passTransitionId - }; - } else { - return { - id: failTransitionId - }; - } - } - - /** - * - * @param cardName - * @param sprintId - * @returns - */ - getCreateRegressionCardRequestBody(cardName: string, sprintId: number) { - const body: JiraIssueFields = { - summary: cardName, - description: { - content: [ - { - "content": [ - { - "text": 'Card to hold regression test results for this sprint.', - "type": "text" - } - ], - "type": "paragraph" - } - ], - "type": "doc", - "version": 1 - }, - project: { - key: jiraProjectKey - }, - issuetype: { id: this.userStoryTypeId!}, - parent: { key: jiraEpicKey }, - customfield_10007: sprintId, - customfield_13100: { id: '557058:a314fc5b-aed9-4472-90f8-00f106e06207' } // Mark UAT Tester as N/A - } - return body; - } - - /** - * Grabs parent card and existing subtasks. - */ - async loadReporterData() { - let parentCard: GetIssueResponse; - await this.loadJiraIssueTypes(); - if (isRegressionRun) { - console.log('JiraWritebackReporter >> Searching for current regression card...'); - const sprint = await this.jiraApiUtil.getCurrentSprint(); - if (!sprint) { - console.error('JiraWritebackReporter >> Could not find current sprint'); - } else { - console.log(`JiraWritebackReporter >> Found sprint with id '${sprint.id}' called '${sprint.name}'`); - } - const regressionCardName = `Playwright Automated Regression Tests ${sprint?.name}`; - const parentRes = await this.jiraApiUtil.getJqlSearchIssue({ jql: `sprint = ${sprint?.id} and summary ~ "${regressionCardName}"` }); - if (parentRes.data.issues.length > 1) { - console.log('JiraWritebackReporter >> WARNING: Multiple regression cards found. Using first one.'); - parentCard = (await this.jiraApiUtil.getIssue(parentRes.data.issues[0].id!)).data; - await this.jiraApiUtil.postTransitionIssue(parentCard.id!, { - transition: { - id: inTestTransitionId - } - }); - } else if (parentRes.data.issues.length < 1) { - // NO regression card found. Make one. - console.log('JiraWritebackReporter >> No regression card was found for this sprint. Creating one.'); - const fields = this.getCreateRegressionCardRequestBody(regressionCardName, sprint!.id); - const regressionCard: JiraIssue = { - fields: fields, - transition: { - id: inTestTransitionId - } - }; - const createRes = await this.jiraApiUtil.postCreateIssue(regressionCard); - regressionCard.id = createRes.data.id; - regressionCard.key = createRes.data.key; - parentCard = regressionCard; - } else { - // Found one - console.log('JiraWritebackReporter >> Found one regression card. Using it.'); - parentCard = (await this.jiraApiUtil.getIssue(parentRes.data.issues[0].id!)).data; - await this.jiraApiUtil.postTransitionIssue(parentCard.id!, { - transition: { - id: inTestTransitionId - } - }); - } - jiraCardNumber = parentCard.key!; - console.log(`JiraWritebackReporter >> Retrieved current regression card: ${parentCard.key}: ${parentCard.fields.summary}`); - } else { - console.log('JiraWritebackReporter >> Searching for parent card...'); - const parentRes = await this.jiraApiUtil.getIssue(jiraCardNumber); - parentCard = parentRes.data; - console.log(`JiraWritebackReporter >> Retrieved parent card: ${parentCard.key}: ${parentCard.fields.summary}`); - } - - console.log(`JiraWritebackReporter >> Searching for all subtasks of parent card '${jiraCardNumber}'...`); - const subtaskIds = parentCard.fields.subtasks?.map(subtask => { - return subtask.id; - }); - - if (subtaskIds && subtaskIds.length > 0) { - for (let i = 0; i < subtaskIds.length; i+=50) { - const batch = subtaskIds.slice(i, i+50); - const subTasksRes = await this.jiraApiUtil.postBulkFetchIssues({ issueIdsOrKeys: batch }); - this.existingSubtasks.push(...subTasksRes.data.issues); - } - console.log('JiraWritebackReporter >> Subtasks retrieved.'); - } else { - console.log('JiraWritebackReporter >> No subtasks were found.'); - } - - } - - /** - * Bulk creates test cases and bugs in batches of up to 50. Bulk transitions existing test case subtasks. - */ - async writeResults() { - for (let i = 0; i < this.issuesToCreate.length; i+=50) { - const batch = this.issuesToCreate.slice(i, i + 50); - console.log('JiraWritebackReporter >> Creating issue batch...'); - // fire request - await this.jiraApiUtil.postBulkCreateIssue({ issueUpdates: batch }); - console.log('JiraWritebackReporter >> Issue batch created.'); - } - - if (this.issuesToPass.length > 0) { - console.log('JiraWritebackReporter >> Transitioning passed test cases to "Pass"...') - await this.jiraApiUtil.postBulkTransitionIssues( { - bulkTransitionInputs: [{ - selectedIssueIdsOrKeys: this.issuesToPass, - transitionId: passTransitionId - }], - sendBulkNotification: false - }); - console.log('JiraWritebackReporter >> Transition success.'); - } - - if (this.issuesToFail.length > 0) { - console.log('JiraWritebackReporter >> Transitioning failed test cases to "Fail"...') - await this.jiraApiUtil.postBulkTransitionIssues( { - bulkTransitionInputs: [{ - selectedIssueIdsOrKeys: this.issuesToFail, - transitionId: failTransitionId - }], - sendBulkNotification: false - }); - console.log('JiraWritebackReporter >> Transition success.') - } - } - - /** - * Builds and loads appropriate response based on test result. This can be a test subtask/bug subtask or a call to transition a test subtask. - * @param test TestCase from onTestEnd() - * @param result TestResult from onTestEnd() - * @returns Void - */ - loadIssue(test: TestCase, result: TestResult) { - if (result.status === 'skipped') return; - if (result.status !== 'passed' && result.retry < test.retries) return; // Skip if test case failed and this isn't the last retry. - - let existingTestSubtask: JiraIssue | undefined = undefined; - let existingBug: JiraIssue | undefined = undefined; - const subtaskTransition = this.getSubtaskTransition(result)!; // Get either a Pass or Fail transition depending on test results. - - console.log('JiraWritebackReporter >> Checking for existing subtasks for this test...'); - for (const card of this.existingSubtasks) { - if (card.fields.issuetype?.id === this.testCaseTypeId) { - if (card.fields.summary === test.title) { - existingTestSubtask = card; - console.log('JiraWritebackReporter >> Found existing test subtask.'); - } - } else if (card.fields.issuetype?.id === this.bugTypeId) { - if (new RegExp(`^TEST FAILED [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]: ${test.title}$`).test(card.fields.summary)) { - existingBug = card; - console.log('JiraWritebackReporter >> Found existing bug.'); - } - } - } - if (!(existingTestSubtask || existingBug)) { - console.log('JiraWritebackReporter >> No existing test subtask or bug was found.') - } - - const subTask = this.getCreateTestSubtask(test, result); // Will return undefined if test status is 'skipped' - const bug = this.getCreateBug(test, result); // Will return undefined if we don't need one - if (subTask) { - // Create or Edit Subtask - if (existingTestSubtask) { - if (result.status === 'passed') { - this.issuesToPass.push(existingTestSubtask.key!); - } else { - this.issuesToFail.push(existingTestSubtask.key!); - } - } else { - this.issuesToCreate.push({ - fields: subTask, - transition: subtaskTransition - }); - } - } - - if (bug) { - // Create or Edit Bug - if (existingBug) { - // Leave it alone. This reporter should not modify existing bugs. - } else { - this.issuesToCreate.push({ - fields: bug - }); - } - } - } - - /** - * This function loads calls to loadIssue() in an array to be executed when the necessary information from the Jira API is available. - * @param test - * @param result - */ - onTestEnd(test: TestCase, result: TestResult) { - this.ortoniReport.onTestEnd(test, result); - this.loadIssueCalls.push(() => { this.loadIssue(test, result); }); - } - - /** - * Makes calls to load and execute API calls to Jira. - * @param result - * @returns Promise to write results to Jira. - */ - onEnd(result: FullResult): Promise<{ status?: FullResult["status"]; } | undefined | void>|void { - return this.ortoniReport.onEnd(result).then(async () => { - await this.loadReporterData().then(async () => { - this.loadIssueCalls.map(fn => fn()); - await this.writeResults(); - }).then(async () => { - console.log('JiraWritebackReporter >> Uploading Ortoni HTML Report to Jira...'); - await this.jiraApiUtil.postUploadAttachment(jiraCardNumber, `${reportConfig.folderPath}/${reportConfig.filename}`); - console.log('JiraWritebackReporter >> Uploaded Ortoni HTML Report to Jira.'); - console.log(`JiraWritebackReporter >> Posted necessary changes for '${jiraCardNumber}'`); - }); - }); - } - - onBegin(config: FullConfig, suite: Suite): Promise { - return this.ortoniReport.onBegin(config, suite); - } - - onError(error: TestError): void { - return this.ortoniReport.onError(error); - } - - onExit(): Promise { - return this.ortoniReport.onExit(); - } - - onStdOut(chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void { - return this.ortoniReport.onStdOut(chunk, test, result); - } -} \ No newline at end of file diff --git a/playwright-tests/impl/utils/DateUtils.ts b/playwright-tests/impl/utils/DateUtils.ts deleted file mode 100644 index d22047c11..000000000 --- a/playwright-tests/impl/utils/DateUtils.ts +++ /dev/null @@ -1,35 +0,0 @@ -export function formatDate(date: Date) { - const isoString = date.toISOString(); - return isoString.slice(0, 10); -} - -export function formatDateForFilename(date: Date) { - const year = date.getFullYear(); - const month = String(date.getMonth() + 1).padStart(2, '0'); - const day = String(date.getDate()).padStart(2, '0'); - const hour = String(date.getHours()).padStart(2, '0'); - const minute = String(date.getMinutes()).padStart(2, '0'); - return `${year}${month}${day}_${hour}${minute}`; -} - -export function formatTime(date: Date) { - return date.toLocaleTimeString('en-US', { - hour: 'numeric', - minute: '2-digit', - hour12: true - }); -} - -export function getNextWeekday(date?: Date) { - if (!date) { - date = new Date(); - date.setHours(8,0,0,0); - } - const dayOfWeek = date.getDay(); - const daysToAdd = dayOfWeek === 5? 3: 1; // Add 3 days if today is friday. Otherwise add 1. - - const nextDay = new Date(date); - nextDay.setDate(date.getDate() + daysToAdd); - - return nextDay; -} \ No newline at end of file diff --git a/playwright-tests/impl/utils/EnumUtils.ts b/playwright-tests/impl/utils/EnumUtils.ts deleted file mode 100644 index 3635989c0..000000000 --- a/playwright-tests/impl/utils/EnumUtils.ts +++ /dev/null @@ -1,76 +0,0 @@ -function isFlags(enumObj: object): boolean { - const values = Object.values(enumObj).filter(v => typeof v === "number"); - return values.some(v => v !== 0 && (v & (v - 1)) === 0); -} - -function isValidEnumValue(value: any, enumType: object): boolean { - if (isFlags(enumType)) { - const allFlags = Object.values(enumType).reduce((acc, val) => typeof val === "number" ? acc | val : acc, 0); - return typeof value === "number" && (value & allFlags) === value; - } else { - return Object.values(enumType).includes(value); - } -} - -function getEnumValues(enumObj: object): string[] | number[] { - if (!isFlags(enumObj)) - return Object.values(enumObj); - return Object.values(enumObj).filter(value => typeof value === "number") as number[]; -} - -function getEnumString(enumObj: T, flags: number): string { - if (flags === 0) - return Object.keys(enumObj).find(key => enumObj[key] === 0) || 'None'; - - const attributes = Object.entries(enumObj).filter(([key, value]) => - typeof value === 'number' && value !== 0 && (flags & value) === value) - .map(([key]) => key); - - return attributes.length === 1 ? attributes[0] : attributes.join(', '); -} - -function validateEnumProperty(json: any, property: string, enumType: object): number | string | null { - if (json.hasOwnProperty(property) && isValidEnumValue(json[property], enumType)) - return json[property]; - return null; -} - -function hasFlag(value: number | string, flag: number | string, enumType: object): boolean { - if (isFlags(enumType)) - return typeof value === "number" && typeof flag === "number" && (value & flag) === flag; - else - return value === flag; -} - -function addFlag(value: number, flag: number, enumType: object): number { - if (isFlags(enumType)) - return value | flag; - else - throw new Error("Attempted to add flag on non-flags enum"); -} - -function removeFlag(value: number, flag: number, enumType: object): number { - if (isFlags(enumType)) - return value & ~flag; - else - throw new Error("Attempted to remove flag on non-flags enum"); -} - -function toggleFlag(value: number, flag: number, enumType: object): number { - if (isFlags(enumType)) - return value ^ flag; - else - throw new Error("Attempted to toggle flag on non-flags enum"); -} - -const EnumUtils = { - hasFlag, - addFlag, - removeFlag, - toggleFlag, - validateEnumProperty, - getEnumValues, - getEnumString -}; - -export default EnumUtils; \ No newline at end of file diff --git a/playwright-tests/impl/utils/FakerUtils.ts b/playwright-tests/impl/utils/FakerUtils.ts deleted file mode 100644 index d406b13a5..000000000 --- a/playwright-tests/impl/utils/FakerUtils.ts +++ /dev/null @@ -1,56 +0,0 @@ -export default class FakerUtils { - private static NUMBERS = '0123456789'; - private static UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - private static LOWERCASE = 'abcdefghijklmnopqrstuvwxyz'; - private static ALPHABET = FakerUtils.UPPERCASE + FakerUtils.LOWERCASE; - private static ALPHANUMERIC = FakerUtils.NUMBERS + FakerUtils.ALPHABET; - - private static generateRandomString(length: number, characters: string): string { - return Array.from(crypto.getRandomValues(new Uint8Array(length))) - .map(byte => characters[byte % characters.length]) - .join(''); - } - - public static generateRandomNumber(min: number, max: number): number { - const range = max - min + 1; - const bytesNeeded = Math.ceil(Math.log2(range) / 8); - const randomBytes = new Uint8Array(bytesNeeded); - crypto.getRandomValues(randomBytes); - const randomValue = randomBytes.reduce((acc, byte) => (acc << 8) + byte, 0); - return min + (randomValue % range); - } - - public static getRandomTestID(): string { - return FakerUtils.generateRandomString(8, FakerUtils.ALPHANUMERIC); - } - - public static getRandomProperty(obj: Record): string { - const keys = Object.keys(obj); - const randomIndex = FakerUtils.generateRandomNumber(0, keys.length - 1); - return keys[randomIndex]; - } - - public static getRandomTail(registrationPrefix: string = "XX", testID: string = ""): string { - return FakerUtils.formatString(FakerUtils.generateRandomString(8, FakerUtils.ALPHANUMERIC)); - } - - public static getRandomEmail(domainSuffix: string = "@test.com", testID: string = ""): string { - const retval = FakerUtils.formatString("{0}{1}", FakerUtils.generateRandomString(8, FakerUtils.ALPHANUMERIC), domainSuffix); - return retval; - } - - public static getRandomLastName(testID: string = " - "): string { - return FakerUtils.formatString(" - {0}", FakerUtils.generateRandomString(21, FakerUtils.ALPHABET)); - } - - public static getObjectName(prefix: string, testID: string = ""): string { - return FakerUtils.formatString("{0} - {1}", prefix, FakerUtils.generateRandomString(21, FakerUtils.ALPHANUMERIC)); - } - - private static formatString(template: string, ...args: (string | (() => string))[]): string { - return template.replace(/\{(\d+)\}/g, (match, index) => { - const arg = args[parseInt(index)]; - return typeof arg === 'function' ? arg() : arg || ''; - }); - } -} \ No newline at end of file diff --git a/playwright-tests/impl/utils/FileUtils.ts b/playwright-tests/impl/utils/FileUtils.ts deleted file mode 100644 index 3f81f0c0a..000000000 --- a/playwright-tests/impl/utils/FileUtils.ts +++ /dev/null @@ -1,22 +0,0 @@ -import fs from 'fs'; -import path from 'path'; - -export function writeFileToLocalCache(fileNameWithExtension: string, fileContents: string) { - const folderPath = path.join(process.cwd(), '.debug', '.cache'); - const filePath = path.join(folderPath, fileNameWithExtension); - - - try { - // Create the folder if it doesn't exist - if (!fs.existsSync(folderPath)) { - fs.mkdirSync(folderPath, { recursive: true }); - } - - // Write the data to the file - fs.writeFileSync(filePath, fileContents); - - console.log(`File "${filePath}" created successfully.`); - } catch (error) { - console.error('Error creating the file:', error); - } -} diff --git a/playwright-tests/impl/utils/HttpUtils.ts b/playwright-tests/impl/utils/HttpUtils.ts deleted file mode 100644 index ec39d8036..000000000 --- a/playwright-tests/impl/utils/HttpUtils.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { Page } from '@playwright/test'; -import { type AxiosInstance, type AxiosResponse } from 'axios'; -import * as fs from 'fs'; -import * as path from 'path'; - -export async function httpGet(client: AxiosInstance, url: string): Promise { - const [isSuccess, response] = await handleHttp(client.get(url)); - if(isSuccess) { - return response; - } - - console.error(`An error occurred calling GET ${url}\nError:${response}`); - throw response; -} - -export async function httpPost(client: AxiosInstance, url: string, data: D): Promise { - const [isSuccess, response] = await handleHttp(client.post(url, data)); - if(isSuccess) { - return response; - } - - console.error(`An error occurred calling POST ${url}\nError:${response}`); - throw response; -} - -export function handleHttp(request: Promise>): Promise<[isSuccess: true, data: T] | [isSuccess: false, error: Error]> { - return request.then(data => { - return [true, data.data] as [true, T] - }).catch((error: Error) => { - return [false, error] as [false, Error] - }) -} - -export function buildQueryString(data: T): URLSearchParams { - const params: Record = {}; - for (const key in data) { - const value = data[key]; - params[key] = `${value}`; - } - return new URLSearchParams(params); -} - -export function forceAPIError(page: Page, endpoint: string) { - page.route('**/*', (route) => { - return route.request().url().includes(endpoint) - ? route.abort() - : route.continue() - }); -} - -// Utility method to return mock response based on endpoint and scenario -export function getMockedApiResponse(endpoint: string, scenario: string): object | null { - const mockResponsesDir = path.resolve(__dirname, '../../tests/mockResponses'); - const configFilePath = path.join(mockResponsesDir, 'mockResponsesConfig.json'); - - if (fs.existsSync(configFilePath)) { - const config = JSON.parse(fs.readFileSync(configFilePath, 'utf-8')); - const scenarioConfig = config[scenario]; - const commonConfig = config['common']; - - let mockFilePath = scenarioConfig ? scenarioConfig[endpoint] : null; - if (!mockFilePath && commonConfig) { - mockFilePath = commonConfig[endpoint]; - } - - if (mockFilePath) { - const filePath = path.join(mockResponsesDir, mockFilePath); - if (fs.existsSync(filePath)) { - const mockResponse = fs.readFileSync(filePath, 'utf-8'); - return JSON.parse(mockResponse); - } - } - } - - return null; -} - -// Utility method for mocking API responses -export function mockApiResponse(page: Page, endpoint: string, scenario: string, mockTestingFlag: boolean) { - const mockResponse = getMockedApiResponse(endpoint, scenario); - page.route(`**/${endpoint}`, route => { - if (mockResponse && mockTestingFlag) { - route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify(mockResponse) - }); - } else { - route.continue(); - } - }); -} \ No newline at end of file diff --git a/playwright-tests/impl/utils/LoggingUtils.ts b/playwright-tests/impl/utils/LoggingUtils.ts deleted file mode 100644 index 1d0b10c07..000000000 --- a/playwright-tests/impl/utils/LoggingUtils.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { ConsoleColor, ResultTypes } from "@business-logic/types/Enums"; - -export default class LoggingUtils { - - public static CONSOLE_WIDTH: number = 100; - //public static ICON_OK: string = "✅"; - public static ICON_OK: string = "\u2705"; - //public static ICON_SKIP: string = "⏩"; - public static ICON_SKIP: string = "\u23ED"; - //public static ICON_WARNING: string = "⚠️"; - public static ICON_WARNING: string = "\u26A0\uFE0F"; - //public static ICON_FAIL: string = "❗"; - public static ICON_FAIL: string = "\u2757"; - - public static log(message: string | null, color: ConsoleColor = ConsoleColor.Default): void { - if (message == null) - return; - console.log(`${color}%s${ConsoleColor.Reset}`, message); - } - - public static icon(value: boolean): string; - public static icon(value: ResultTypes): string; - public static icon(value: any): string { - if (typeof value === "boolean") - return value ? this.ICON_OK : this.ICON_FAIL; - - switch (value) { - case ResultTypes.Failure: - return this.ICON_FAIL; - case ResultTypes.Success: - return this.ICON_OK; - case ResultTypes.Skipped: - return this.ICON_SKIP; - } - return ""; - } - - public static logFunc(name: string, value: string | null = null, result: boolean | null = null): string { - let icon = this.ICON_SKIP; - if (result != null) - icon = result ? this.ICON_OK : this.ICON_FAIL; - - if (value != null) - return `${this.getShortDateTime()} [${this.centerPadString(`${name}: ${this.truncateString(value)}`)}] -> ${icon}`; - - return `${this.getShortDateTime()} [${this.centerPadString(name)}] -> ${icon}`; - } - - public static logValidate(text: string, success: boolean) { - return `${this.getShortDateTime()} [${this.centerPadString(text)}] -> ${success ? this.ICON_OK : this.ICON_FAIL}`; - } - - public static truncateString(value: any, maxLength: number = this.CONSOLE_WIDTH): string { - let str = typeof value === 'string' ? value : String(value); - str = str.replace(/\s+/g, ' ').trim(); - if (str.length <= maxLength) { - return str; - } - return str.slice(0, maxLength - 2) + '..'; - } - - public static sanitizeFileName(input: string): string { - // Remove characters that are invalid in both Windows and Linux file systems - let sanitized = input.replace(/[<>:"/\\|?*\x00-\x1F]/g, ''); - - // Remove leading and trailing spaces and dots - sanitized = sanitized.trim().replace(/^\.+|\.+$/g, ''); - - // Replace remaining dots and spaces with underscores - sanitized = sanitized.replace(/[\s.]+/g, '_'); - - // Ensure the name isn't empty after sanitization - if (sanitized.length === 0) { - sanitized = 'unnamed'; - } - - // Truncate to a reasonable maximum length (e.g., 255 characters) - sanitized = sanitized.slice(0, 255); - - return sanitized; - } - - public static replaceEmptyLinesWithMiddleDot(input: string): string { - const emptyLinesRegex: RegExp = /(.+?)(\n\s*\n)+/g; - - return input.replace(emptyLinesRegex, (_match, line) => { - return line + '·\n'; - }).replace(/\n$/, ''); - } - - private static centerPadString(str: string, length: number = this.CONSOLE_WIDTH): string { - if (str.length >= length) { - return this.truncateString(str); - } - - str = this.truncateString(str); - - const totalPadding = length - str.length; - const leftPadding = Math.ceil(totalPadding / 2); - const rightPadding = Math.floor(totalPadding / 2); - - return ' '.repeat(leftPadding) + str + ' '.repeat(rightPadding); - } - - private static getShortDateTime() { - return new Date().toLocaleString('en-US', { - year: '2-digit', - month: '2-digit', - day: '2-digit', - hour: '2-digit', - minute: '2-digit', - second: '2-digit', - hour12: false - }); - } - - public static normalizeSalesForceType(input: string, prefix: string = "Apttus_Config2__", suffix: string = "__c") { - let result = input; - - if (result.startsWith(prefix)) - result = result.slice(prefix.length); - - if (result.endsWith(suffix)) - result = result.slice(0, -suffix.length); - - return result; - } -} \ No newline at end of file diff --git a/playwright-tests/impl/utils/ParsingUtils.ts b/playwright-tests/impl/utils/ParsingUtils.ts deleted file mode 100644 index b72e1bbf8..000000000 --- a/playwright-tests/impl/utils/ParsingUtils.ts +++ /dev/null @@ -1,34 +0,0 @@ - -/** - * Parses a string containing a representation of currency, and returns a typed number. Can handle - * different types of currency represenations. - * - * USD 12,345.65 -> 12345.65 - * (USD 12345.00) -> -12345 - * - * @param text String containing currency representation - * @param currencyCode Optionally define different currency code - * @returns Parsed currency with type number - */ -export function parseCurrency(text: string, currencyCode: string = "USD"): number { - // TODO: Add ability to handle null fields/not treat null as 0 - KK 9/12/24 - // Base case, if text can be cast as a number then work is done - if (!isNaN(+text)) return +text; - // Remove parentheses and continue parsing, multiply return by -1 to preserve negative value - if (text.charAt(0) === '(') return -1 * parseCurrency(text.substring(1, text.length - 1)); - // Remove currency code prefix and continue parsing - if (text.split(' ')[0] === currencyCode) return parseCurrency(text.split(' ')[1]); - // Remove commas and cast to number - return Number(text.split(',').join('')); -} - -/** - * @param text - * @returns - */ -export function parseNumberOrCurrency(text: string): number | string { - if (!isNaN(+text)) return +text; - else if (text.charAt(0) === '(') return -1 * parseCurrency(text.substring(1, text.length - 1)); - else if (text.split(' ')[0] === "USD") return parseCurrency(text); - else return text; -} diff --git a/playwright-tests/impl/utils/PropertyUtils.ts b/playwright-tests/impl/utils/PropertyUtils.ts deleted file mode 100644 index ac95d8a71..000000000 --- a/playwright-tests/impl/utils/PropertyUtils.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { ValidationResult } from "@business-logic/types/RuleEngine"; -import EnumUtils from "./EnumUtils"; - -export type ExtractName = { [K in keyof T]: () => K; }; - -type GetValueOptions = { - isRequired: boolean; -}; - -function isNullOrWhiteSpace(input: unknown): boolean { - if (typeof input !== "string") - return input == null; - return input.trim().length === 0; -} - -// Matches: '() => _Enums.*****', e.g.: '() => _Enums.ModificationTypes' -// Matches: '() => *****', e.g.: '() => ModificationTypes' -// Returns: EnumName, e.g.: 'ModificationTypes' -function getEnumName(propertySelector: () => object): string { - const functionString = propertySelector.toString(); - const match = functionString.match(/\(\s*\)\s*=>\s*(?:_?[A-Z]\w*\.)?(\w+)(?::)?/); - return match ? match[1] : "Unknown"; -} - -// Matches: 'x => x.*****', e.g.: 'x => x.name', 'x => x.tags' -// Returns: PropertyName, e.g.: 'name', 'tags' -function getNameof(propertySelector: (obj: T) => any): string { - const propertyString = propertySelector.toString(); - const match = propertyString.match(/(?:=>|return)\s*([\w\s.]+)/); - - if (match && match[1]) { - const parts = match[1].split('.'); - return parts[parts.length - 1].trim(); - } - - throw new Error(`Invalid property selector: ${propertyString}`); -} - -function getValueOrNull(json: any, propertySelector: (obj: T) => any): any | null { - if (json == null) - return null; - - const property = getNameof(propertySelector); - - if (json.hasOwnProperty(property)) - return json[property]; - - return null; -} - -function getValue(json: any, typeName: string, validationResults: ValidationResult[], options: GetValueOptions, propertySelector: (obj: T) => any): any | null { - const retval = getValueOrNull(json, propertySelector); - - if (retval == null) - validationResults.push(options.isRequired ? ValidationResult.FromFailure(`Value for ${typeName}.${getNameof(propertySelector)} is null but is required!`) : ValidationResult.FromSuccess(retval, `Value for ${typeName}.${getNameof(propertySelector)} is null but is NOT required.`)); - else { - if (isNullOrWhiteSpace(retval)) - validationResults.push(ValidationResult.FromFailure(`Value for ${typeName}.${getNameof(propertySelector)} is empty!`)); - else - validationResults.push(ValidationResult.FromSuccess(retval, `Value for ${typeName}.${getNameof(propertySelector)} is valid.`)); - } - - return retval; -} - -function hasProperty(json: any, typeName: string, validationResults: ValidationResult[], options: GetValueOptions, propertySelector: (obj: ExtractName) => () => keyof T): boolean { - const retval = json.hasOwnProperty(getNameof(propertySelector)); - - if (retval) - validationResults.push(ValidationResult.FromSuccess(retval, `Value for ${typeName}.${getNameof(propertySelector)} is valid.`)); - else - validationResults.push(options.isRequired ? ValidationResult.FromSuccess(retval, `Value for ${typeName}.${getNameof(propertySelector)} is not defined but is required!`) : ValidationResult.FromFailure(`Value for ${typeName}.${getNameof(propertySelector)} is not defined but is NOT required!`)); - - return retval; -} - -function getEnumValueOrNull(json: any, enumType: object, propertySelector: (obj: T) => any): any | null { - if (json == null) - return null; - - const property = getNameof(propertySelector); - const retval = EnumUtils.validateEnumProperty(json, property, enumType); - - if (retval != null) - return retval; - else if (Object.values(enumType).includes(json[property])) - return json[property]; - - return null; -} - -function getEnumValue(json: any, typeName: string, validationResults: ValidationResult[], enumType: object, enumTypeInstance: () => object, options: GetValueOptions, propertySelector: (obj: T) => any): any | null { - const retval = getEnumValueOrNull(json, enumType, propertySelector); - - if (retval == null) - validationResults.push(options.isRequired ? ValidationResult.FromFailure(`Value for ${typeName}.${getNameof(propertySelector)} [${getEnumName(enumTypeInstance)}] is null but is required!`) : ValidationResult.FromSuccess(retval, `Value for ${typeName}.${getNameof(propertySelector)} [${getEnumName(enumTypeInstance)}] is null but is NOT required.`)); - else - validationResults.push(ValidationResult.FromSuccess(retval, `Value for ${typeName}.${getNameof(propertySelector)} is valid.`)); - - return retval; -} - -export { getEnumName, getEnumValueOrNull, getNameof, getValueOrNull }; - -const PropertyUtils = { - hasProperty, - getValue, - getEnumValue -}; - -export default PropertyUtils; \ No newline at end of file diff --git a/playwright-tests/impl/utils/TaggingUtils.ts b/playwright-tests/impl/utils/TaggingUtils.ts deleted file mode 100644 index 00a99fae5..000000000 --- a/playwright-tests/impl/utils/TaggingUtils.ts +++ /dev/null @@ -1,32 +0,0 @@ -export function formatTag(text: string): string { - return "@" + text.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, (match, index) => { - if (+match === 0) return ""; // Remove non-alphanumeric characters - return index === 0 ? match.toLowerCase() : match.toUpperCase(); - }); -} -/** - * @description - Use this to add calculated/standardized/randomized tags to scenarioData prior to running. Randomly adds a smoke tag to 1 of the testCases. - * @param scenarioData - the data from your test case - * @returns scenarioData, but with added tags. - */ - -export function getRandomTestName(scenarioData: any) : string { - const testCaseNames: string[] = Object.keys(scenarioData); - const totalKeys = testCaseNames.length - const randomIndex = Math.floor(Math.random() * totalKeys) - 1; - const randomKey = testCaseNames[randomIndex]; - - return randomKey; -} - -export function metaTags(currentTestName: string, randomTestName: string) : string [] { - return currentTestName == randomTestName ? ["@smoke", "@standardRegression"] : ["@standardRegression"] -} - -export function matchAndReplaceContactDataTag(data: string[], replacement: string): string[] { - return data.map((value) => value.replace(/[{]{2}contact[}]{2}/, replacement)); -} - -export function matchAndReplaceAccountDataTag(data: string[], replacement: string): string[] { - return data.map((value) => value.replace(/[{]{2}account[}]{2}/, replacement)); -} diff --git a/playwright-tests/impl/utils/ThrowUtils.ts b/playwright-tests/impl/utils/ThrowUtils.ts deleted file mode 100644 index 2debfca36..000000000 --- a/playwright-tests/impl/utils/ThrowUtils.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { error } from "console"; - - -export function throwIf(conditionFunction: () => boolean, errorMessage: string): void { - if (conditionFunction()) - throw new Error(errorMessage); -} - - -export function throwNotYetImplemented(nameOfThingNotImplemented: string) { - throw new Error(`${nameOfThingNotImplemented} has not yet been implemented.`) -} \ No newline at end of file diff --git a/playwright-tests/impl/utils/TimingUtils.ts b/playwright-tests/impl/utils/TimingUtils.ts deleted file mode 100644 index e88efc0ca..000000000 --- a/playwright-tests/impl/utils/TimingUtils.ts +++ /dev/null @@ -1,273 +0,0 @@ -import { expect, Locator, Page } from "@playwright/test"; -import LoggingUtils from "./LoggingUtils"; -import { DateTime } from "luxon"; - - -export type TimeoutOpts = { - /** - * @description timeout Commonly referred to for an entire method; exists to allow developers to specify their own timeout whout overriding defaults - */ - - timeout: number - /** - * @description timeout_tiny use for exceedingly small waits, as in, waiting for label to contain the test you just typed into it. - */ - timeoutTiny: number - - /** - * @description timeout_short for relatively quick opperations, such as waiting for a dropdown to render - */ - timeoutShort: number - - /** - * @description timeout_medium for moderately slow operations, such as a new modal rendering, or a calculated field value being updated, or an API Call - */ - timeoutMedium: number - - /** - * @description timeout_long for high-risk, slow operations. Waiting for the minicart to load, waiting for login, or waiting for screen-to-screen navigation. - */ - timeoutLong: number - - /** - * @description for when things are really, really bad. - */ - timeoutConga: number -} - -export const timeoutOptDefaults: TimeoutOpts = { - timeout: 60_000, - timeoutTiny: +(process.env.TIMEOUT_TINY ?? 500), - timeoutShort: +(process.env.TIMEOUT_SHORT ?? 5000), - timeoutMedium: +(process.env.TIMEOUT_MEDIUM ?? 30_000), - timeoutLong: +(process.env.TIMEOUT_LONG ?? 180_000), - timeoutConga: +(process.env.TIMEOUT_CONGA ?? 500_000), -} - -export type WaitUntilOpts = { - delayBetweenChecks: number, - continueOnTimeoutError: boolean, - anticipatedConditionResult: boolean, - conditionName: string, - beginWaitingMessage: string, - delayBetweenChecksMessage: string, - timeoutErrorMessage: string, - successMessage: string, - ignoreErrorsFromConditionFunction: boolean, - -} -export const waitUntilOptDefaults: WaitUntilOpts = { - delayBetweenChecks: 3000, - continueOnTimeoutError: false, - anticipatedConditionResult: true, - conditionName: "", - beginWaitingMessage: "", - delayBetweenChecksMessage: "", - timeoutErrorMessage: "Timed Out", - successMessage: "", - ignoreErrorsFromConditionFunction: true, -} - -/** - * @description repeatedly execute an asynchronous conditional lambda until a given outcome occurs, or the method times-out. Useful for hedgning against GUI race conditions. - * @param conditionFunction the condition lambda. Example: ()=>{await return myPage.someButton.isVisible()} - * @param options standard Timeout and WaitUntil Options. - * @returns true or false - the outcome of the waituntil. - */ - -export async function waitUntil(conditionFunction: (...args: any[]) => Promise, options: Partial = {}): Promise { - const opts = { ...waitUntilOptDefaults, ...timeoutOptDefaults, ...options } - - const timeoutAt = Date.now() + opts.timeout; - let waitUntilHasTimedOut = false; - let conditionHasBeenMet = false; - do { - try { - const conditionResult = await conditionFunction() - conditionHasBeenMet = conditionResult == opts.anticipatedConditionResult - } - catch (e) { - if (!opts.ignoreErrorsFromConditionFunction) { - throw e - } - } - waitUntilHasTimedOut = Date.now() > timeoutAt - if (!waitUntilHasTimedOut && !conditionHasBeenMet) { - await delay(opts.delayBetweenChecks) - } - else if (waitUntilHasTimedOut && !opts.continueOnTimeoutError) { - throw new Error(opts.timeoutErrorMessage) - } - } - while (!conditionHasBeenMet || waitUntilHasTimedOut) - return conditionHasBeenMet; -} - -/** - * @description Order Matters; WaitUntil each condition passes before moving to the next. All conditions must pass in the expected order. - * @param sequentialConditionFunctions an array of async, boolean lambdas to be executed in sqeuance until all have passed. - * @param options standard Timeout and WaitUntil options - */ -export async function waitUntilValueStopsChanging(mercurialValueFunction: (...args: any[]) => Promise, options: Partial = {}): Promise { - const opts = { ...waitUntilOptDefaults, ...timeoutOptDefaults, ...options } - - let lastFoundValue: any = undefined; - const valueHasStoppedChanging = async () => { - const newFoundValue = await mercurialValueFunction(); - if (opts.delayBetweenChecksMessage.length > 0) console.log(`${opts.delayBetweenChecksMessage} - Last Value: ${lastFoundValue}`) - const valueIsStable = (newFoundValue != undefined) && (newFoundValue == lastFoundValue); - lastFoundValue = newFoundValue; - return valueIsStable; - } - await waitUntil(valueHasStoppedChanging, opts) - return lastFoundValue; -} - -/** - * @todo EXPIRIMENTAL! NO UNIT TESTS YET! TODO, add - DF, 5/23 - * @description Order Matters; WaitUntil each condition passes before moving to the next. All conditions must pass in the expected order. - * @param sequentialConditionFunctions an array of async, boolean lambdas to be executed in sqeuance until all have passed. - * @param options standard Timeout and WaitUntil options - */ -export async function waitUntilEach(sequentialConditionFunctions: ((...args: any[]) => Promise)[], options: Partial = {}): Promise { - for (const conditionFunction of sequentialConditionFunctions) { - await waitUntil(conditionFunction, options); - } -} - -/** - * @todo EXPIRIMENTAL! NO UNIT TESTS YET! TODO, add - DF, 5/23 - * @description Order Matters; WaitUntil each condition passes before moving to the next. All conditions must pass in the expected order. - * @param sequentialConditionFunctions an array of async, boolean lambdas to be executed in sequence until all have passed. - * @param options standard Timeout and WaitUntil options - */ -export async function waitUntilAll(sequentialConditionFunctions: ((...args: any[]) => Promise)[], options: Partial = {}): Promise { - for (const conditionFunction of sequentialConditionFunctions) { - await waitUntil(conditionFunction, options); - } -} - -/** - * @todo EXPIRIMENTAL! NO UNIT TESTS YET! TODO, add - DF, 5/23 - * @description Order DOES NOT Matter; WaitUntil ANY condition passes before completing. Use when multiple conditions can give confidence that sufficient waiting has occured. - * @param sequentialConditionFunctions an array of async, boolean lambdas to be executed in psudo-parallel until at least one has passed. - * @param options standard Timeout and WaitUntil options - */ -export async function waitUntilAny(multipleRequiredConditionFunctions: ((...args: any[]) => Promise)[], options: Partial = {}): Promise { - const anyConditionMet = async (): Promise => { - return multipleRequiredConditionFunctions.filter(async (fun: (...args: any[]) => Promise): Promise => await Function.call(fun)).length > 0; - }; - waitUntil(anyConditionMet, options) -} - -/** - * @param milliseconds delay duration - * @param logDelay defaults to false; if true, logs a waiting message. - */ -export async function delay(milliseconds: number, logDelay = false): Promise { - if (logDelay) { console.log(`delaying ${milliseconds} milliseconds before continuing...`) } - return new Promise((resolve) => setTimeout(resolve, milliseconds)); -} - -/** - * Waits for the page url - * @param partialUrl The string we are looking for in the url, to know we have transitioned to the correct page. - * @param timeout the amount of milliseconds to wait before giving up. - */ -export async function waitForUrlPartialMatch(page: Page, firstPartialUrl: string, timeout = 120_000) { - const startTime = Date.now(); - while (Date.now() - startTime < timeout) { - if (page.url().includes(firstPartialUrl)) { - return; // URL matches the partial string, exit the function - } - await page.waitForTimeout(100); // Wait for 100 milliseconds before checking again - } - throw new Error(`Timed out waiting for URL to match '${firstPartialUrl}'`); -} - -/** - * Run a function repeatedly until it returns true or the timeout is reached. - * - * This function executes the provided asynchronous block function in a loop until it returns true or the specified - * timeout duration has elapsed. Between each attempt, it waits for a specified delay. - * - * @param block - An asynchronous function that returns a boolean value. This function will be executed repeatedly until it returns true. - * @param timeout - The maximum duration to keep attempting to run the block function, in milliseconds. Default is 150000 (150 seconds). - * @param delayMs - The delay duration between each attempt, in milliseconds. Default is 3000 (3 seconds). - * @returns A promise that resolves to a boolean value indicating whether the block function eventually returned true. - * - * @example - * // Example usage: - * const blockFunction = async () => { - * // Some asynchronous condition check - * return await someConditionCheck(); - * }; - * const result = await runUntilTrue(blockFunction, 10000, 1000); - * console.log(result); // Outputs true if blockFunction returned true within the timeout, otherwise false. - */ -export async function runUntilTrue(block: () => Promise, timeout: number = 150000, delayMs: number = 3000){ - const startTime = DateTime.now(); - let attempts = 0; - let evaluatesToTrue = false; - - do { - // If timeout duration has elapsed, stop making attempts - if (DateTime.now().diff(startTime).as('milliseconds') > timeout) { - break; - } - - attempts++; - // If retrying, wait delay duration - if (attempts > 1) await delay(delayMs); - - evaluatesToTrue = await block(); - - } while (!evaluatesToTrue); - - return evaluatesToTrue; -} - -// TODO move this to impl/utils/WaitingUtils when that related pr is available in devleop branch - T.S. 5/20/24 -export async function waitForEither(block1: () => Promise, block2: () => Promise, timeOut: number = 180_000): Promise { - const startTime = Date.now(); - - while (true) { - try { - const result1 = await block1(); - const result2 = await block2(); - - // Check if either result is truthy (i.e., not falsy or undefined) - if (result1 || result2) { - // At least one block returned a truthy value, resolve the promise - return; - } - } catch (error) { - // Handle errors thrown by either block - console.error("An error occurred:", error); - } - - // Check if the timeout has been reached - if (Date.now() - startTime >= timeOut) { - throw new Error(`Timeout of ${timeOut} ms exceeded`); - } - - // Add some delay before checking again - await new Promise(resolve => setTimeout(resolve, 1000)); // Adjust delay as needed - } -} - -/** - * Waits for a specific locator to show up on screen, then disappear. Typically used for things like progress bars. - * @param locator The locator we want to become visible and then become hidden - */ -export async function waitToAppearAndDisappear(locator: Locator): Promise { - try { - await expect(locator).toBeVisible({ timeout: 60000 }); - await expect(locator).toBeHidden({ timeout: 60000 }); - } catch (err) { - if (err instanceof Error) - console.log(LoggingUtils.logFunc(waitToAppearAndDisappear.name, err.message, false)); - else - console.log(LoggingUtils.logFunc(waitToAppearAndDisappear.name, null, false)); - } -} \ No newline at end of file diff --git a/playwright-tests/impl/utils/TryUtils.ts b/playwright-tests/impl/utils/TryUtils.ts deleted file mode 100644 index de30a0695..000000000 --- a/playwright-tests/impl/utils/TryUtils.ts +++ /dev/null @@ -1,132 +0,0 @@ -import LoggingUtils from "./LoggingUtils"; -import { delay, timeoutOptDefaults } from "./TimingUtils"; - -/** - * @description For situations where a Test Framework Exception (i.e., a locator timeout) could be incorrectly thrown based on the state of the Target-Application (i.e., a missing tail number). Use this to throw clearer 'Application Exception' errors under such circumstances. - * @param actionVerb What are you trying to do? Could be 'gotoCatalog', 'addAnEnhancement', etc. Logged as `Attempting to ${actionVerb}` - * @param failureExplenation Be descriptive. What is the context of the failure? If someone unfamiliar with the code base were to see this, how would they know if the error was caused by their code, or by an underlying problem with the Target Application? - * @param actionToAttempt a lambda for the flaky action. - * @returns - */ -export async function tryBusinessAction(actionVerb: string, failureExplenation: string, actionToAttempt: (...args: any[]) => Promise): Promise { - let actionResult: any; - console.log(`Attempting to ${actionVerb}...`) - try { - actionResult = await actionToAttempt(); - } catch (e) { - if (e instanceof Error) { - e.message = e.message + ">>Failure Explenation>> " + failureExplenation; - throw (e); - } else { - throw (new Error("Unknown 'AttemptBusinessAction' State...")) - } - } - console.log(`Successfully executed ${actionVerb}`) - return actionResult; -} - -/** - * @description Brute-Force Flaky GUI activities by reseting and retrying. - * @param actionToTry lambda for whatever flaky action you're trying to take - * @param resetAction lambda for backing out of the problem and returning to a known state. Often, refreshing a browser, or closing a popup. - * @param maxRetries number of times to retry the action - * @param delayBetweenRetries milliseconds between retries - */ -export async function tryResetAndRetry( - actionVerb: string, - actionToTry: (...args: any[]) => Promise, - resetAction: (...args: any[]) => Promise, - maxRetries = 2, - delayBetweenRetries = timeoutOptDefaults.timeoutMedium): Promise { - - for (let i = 1; i <= maxRetries; i++) { - try { - await actionToTry() - } catch { - await delay(delayBetweenRetries); - resetAction(); - } - } -} - -/** - * @description For situations where a Test Framework Exception (i.e., a locator timeout) could be incorrectly thrown based on the state of the Target-Application (i.e., a missing tail number). Use this to throw clearer 'Application Exception' errors under such circumstances. - * @param actionVerb What are you trying to do? Could be 'gotoCatalog', 'addAnEnhancement', etc. Logged as `Attempting to ${actionVerb}` - * @param failureExplenation Be descriptive. What is the context of the failure? If someone unfamiliar with the code base were to see this, how would they know if the error was caused by their code, or by an underlying problem with the Target Application? - * @param actionToAttempt a lambda for the flaky action. - * @returns - */ -export async function tryBusinessActionWithRetries(actionVerb: string, failureExplenation: string, actionToAttempt: (...args: any[]) => Promise, attempts = 3): Promise { - let actionResult: any; - let isSuccessful: boolean = false; - //actionVerb is already a logFunc string - console.log(actionVerb); - - for (let i = 0; i < attempts; i++) { - try { - actionResult = await actionToAttempt(); - isSuccessful = true; - break; // Break loop if actionToAttempt is successful - } catch (e) { - if (e instanceof Error) { - e.message = e.message + ">>Failure Explanation>> " + failureExplenation; - } else { - throw (new Error("Unknown 'AttemptBusinessAction' State")) - } - } - } - - if (!isSuccessful) { - throw new Error(`Failed to ${actionVerb}`); - } - - //actionVerb is already a logFunc string - console.log(actionVerb); - return actionResult; -} - -/** - * Tries to execute a block of code with chances to retry. - * @param {Function} block The block of code to be executed. - * @param {string} [blockDescription=''] A text description of the block (optional). - * @param {number} [maxRetries=3] The maximum number of retry attempts (optional). - * @param {number} [delayMs=1000] The delay between retry attempts in milliseconds (optional). - */ -export async function retry(block: () => Promise, blockDescription: string = '', maxRetries: number = 3, delayMs: number = 1000): Promise { - let retries: number = 0; - if (!blockDescription.length) { - blockDescription = block.toString(); - } - - while (retries < maxRetries) { - console.log(LoggingUtils.logFunc(retry.name, blockDescription)); - try { - return await block(); - } catch (error) { - if (retries === maxRetries - 1) { - throw new Error(`Max retries (${maxRetries}) exceeded. Last error: ${error}`); - } - // wait between retries - await new Promise(resolve => setTimeout(resolve, delayMs)); - retries++; - } - } - // This should not be reached, but just in case - throw new Error(`Unexpected code execution. Max retries (${maxRetries}) exceeded.`); -} - -export async function tryWithRetries(actionBlock: Function, attempts = 3, waitInterval = 1000) { - for (let attempt = 1; attempt <= attempts; attempt++) { - try { - await actionBlock(); - if (attempt > 1) - console.warn(`Had to retry but attempt ${attempt} succeeded!`); - break; // Exit the loop if the action is successful - } catch (error) { - console.error(`Attempt ${attempt} failed!`); - if (attempt < attempts) { - await new Promise(resolve => setTimeout(resolve, waitInterval)); - } - } - } -} \ No newline at end of file diff --git a/playwright-tests/package-lock.json b/playwright-tests/package-lock.json index d06e45696..929a66d4d 100644 --- a/playwright-tests/package-lock.json +++ b/playwright-tests/package-lock.json @@ -17,13 +17,13 @@ "@faker-js/faker": "^9.8.0", "@playwright/test": "^1.52.0", "@types/dotenv-safe": "^8.1.6", - "@types/node": "^22.15.30", + "@types/node": "^22.15.32", "dotenv-safe": "^9.1.0", "eslint": "^9.28.0", "luxon": "^3.6.1", "ortoni-report": "^3.0.2", "playwright-jira-reporter": "^1.0.4", - "safelite-playwright-core": "^1.0.14", + "safelite-playwright-core": "^1.0.20", "typescript": "^5.8.3" } }, @@ -354,9 +354,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.15.30", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.30.tgz", - "integrity": "sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA==", + "version": "22.15.32", + "resolved": "https://pkgs.dev.azure.com/Safelite/Digital/_packaging/DigitalQA/npm/registry/@types/node/-/node-22.15.32.tgz", + "integrity": "sha1-wwHMInW1NaXlS7gdUWsdLpr+BuU=", "dev": true, "license": "MIT", "dependencies": { @@ -3278,9 +3278,9 @@ "peer": true }, "node_modules/safelite-playwright-core": { - "version": "1.0.14", - "resolved": "https://pkgs.dev.azure.com/Safelite/Digital/_packaging/DigitalQA/npm/registry/safelite-playwright-core/-/safelite-playwright-core-1.0.14.tgz", - "integrity": "sha1-e+5FwglTzzRjZeLB4wOHGiOvsXI=", + "version": "1.0.20", + "resolved": "https://pkgs.dev.azure.com/Safelite/Digital/_packaging/DigitalQA/npm/registry/safelite-playwright-core/-/safelite-playwright-core-1.0.20.tgz", + "integrity": "sha1-9y9mZfuQ1RRvwc3vgkyt/DL4EXk=", "dev": true, "license": "ISC", "dependencies": { diff --git a/playwright-tests/package.json b/playwright-tests/package.json index 527ec7058..bc5b9b4ca 100644 --- a/playwright-tests/package.json +++ b/playwright-tests/package.json @@ -25,13 +25,13 @@ "@faker-js/faker": "^9.8.0", "@playwright/test": "^1.52.0", "@types/dotenv-safe": "^8.1.6", - "@types/node": "^22.15.30", + "@types/node": "^22.15.32", "dotenv-safe": "^9.1.0", "eslint": "^9.28.0", "luxon": "^3.6.1", "ortoni-report": "^3.0.2", "playwright-jira-reporter": "^1.0.4", - "safelite-playwright-core": "^1.0.14", + "safelite-playwright-core": "^1.0.20", "typescript": "^5.8.3" }, "private": "true" diff --git a/playwright-tests/pages/AfterpayPage.ts b/playwright-tests/pages/AfterpayPage.ts index aed3fe339..b26949e50 100644 --- a/playwright-tests/pages/AfterpayPage.ts +++ b/playwright-tests/pages/AfterpayPage.ts @@ -1,6 +1,6 @@ import { Locator, Page } from "@playwright/test"; import { BasePage } from "./BasePage"; -import { IPaymentDetails } from "@business-logic/types/CustomerDetails"; +import { IPaymentDetails } from 'safelite-playwright-core'; export class AfterpayPage extends BasePage { readonly page: Page; diff --git a/playwright-tests/pages/BasePage.ts b/playwright-tests/pages/BasePage.ts index 0e8c65219..354e67ef4 100644 --- a/playwright-tests/pages/BasePage.ts +++ b/playwright-tests/pages/BasePage.ts @@ -1,6 +1,6 @@ -import { IAppointmentDetails, ICustomerDetails } from '@business-logic/types/CustomerDetails'; -import Soft from '@business-logic/validations/Soft'; -import { waitUntil } from '@impl/utils/TimingUtils'; +import { ICustomerDetails } from 'safelite-playwright-core'; +import { Soft } from 'safelite-playwright-core'; +import { waitUntil } from 'safelite-playwright-core'; import test, { expect, type Locator, type Page } from '@playwright/test'; import { error } from 'console'; diff --git a/playwright-tests/pages/CCPolicyInfoPage.ts b/playwright-tests/pages/CCPolicyInfoPage.ts index 7151e3c06..22e2372d1 100644 --- a/playwright-tests/pages/CCPolicyInfoPage.ts +++ b/playwright-tests/pages/CCPolicyInfoPage.ts @@ -1,9 +1,9 @@ import { expect, type Locator, type Page } from '@playwright/test'; -import { IClaimDetails, ICustomerDetails } from '@business-logic/types/CustomerDetails'; +import { IClaimDetails, ICustomerDetails } from 'safelite-playwright-core'; import { InsuranceBasePage } from './InsuranceBasePage'; -import { STATE_ABBREVIATIONS } from '@business-logic/constants/StateAbbreviation'; -import { ITestData } from '@business-logic/types/ITestData'; -import { step } from '@business-logic/types/Step'; +import { STATE_ABBREVIATIONS } from 'safelite-playwright-core'; +import { ITestData } from 'framework/TestData'; +import { step } from 'framework/localTypes/Step'; export class CCPolicyInfoPage extends InsuranceBasePage { readonly policyNumber: Locator; diff --git a/playwright-tests/pages/CapabilityQuestionsPage.ts b/playwright-tests/pages/CapabilityQuestionsPage.ts index 3aed26223..f8f7efeb0 100644 --- a/playwright-tests/pages/CapabilityQuestionsPage.ts +++ b/playwright-tests/pages/CapabilityQuestionsPage.ts @@ -1,8 +1,8 @@ import { Page } from "@playwright/test"; import { PartQuestionsPage } from "./PartQuestionPage"; -import { step } from "@business-logic/types/Step"; -import { ITestData } from "@business-logic/types/ITestData"; -import { ProgressBarPercentages } from "@business-logic/types/Enums"; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; export default class CapabilityQuestionsPage extends PartQuestionsPage { url = process.env['BASE_URL']! + '/fmg/?fmgPage=capability-questions'; diff --git a/playwright-tests/pages/ContactDetailsPage.ts b/playwright-tests/pages/ContactDetailsPage.ts index 41ce9de09..472f9db33 100644 --- a/playwright-tests/pages/ContactDetailsPage.ts +++ b/playwright-tests/pages/ContactDetailsPage.ts @@ -1,9 +1,9 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { ICustomerDetails } from '@business-logic/types/CustomerDetails'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; -import { ProgressBarPercentages } from '@business-logic/types/Enums'; +import { ICustomerDetails } from 'safelite-playwright-core'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; export class ContactDetailsPage extends BasePage { readonly page: Page; diff --git a/playwright-tests/pages/CoverageStatementPage.ts b/playwright-tests/pages/CoverageStatementPage.ts index 7085c6794..c1c4369e5 100644 --- a/playwright-tests/pages/CoverageStatementPage.ts +++ b/playwright-tests/pages/CoverageStatementPage.ts @@ -1,8 +1,8 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { InsuranceBasePage } from './InsuranceBasePage'; -import { IClaimDetails } from '@business-logic/types/CustomerDetails'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; +import { IClaimDetails } from 'safelite-playwright-core'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; export class CoverageStatementPage extends InsuranceBasePage { readonly page: Page; diff --git a/playwright-tests/pages/DuplicateCheckPage.ts b/playwright-tests/pages/DuplicateCheckPage.ts index e5f44492c..d296be792 100644 --- a/playwright-tests/pages/DuplicateCheckPage.ts +++ b/playwright-tests/pages/DuplicateCheckPage.ts @@ -1,7 +1,7 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { InsuranceBasePage } from './InsuranceBasePage'; -import { ITestData } from '@business-logic/types/ITestData'; -import { step } from '@business-logic/types/Step'; +import { ITestData } from 'framework/TestData'; +import { step } from 'framework/localTypes/Step'; export class DuplicateCheckPage extends InsuranceBasePage { readonly page: Page; diff --git a/playwright-tests/pages/EndorsementsPage.ts b/playwright-tests/pages/EndorsementsPage.ts index 3b63dcac0..5cff75f17 100644 --- a/playwright-tests/pages/EndorsementsPage.ts +++ b/playwright-tests/pages/EndorsementsPage.ts @@ -1,10 +1,10 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { IEndorsementDetails } from '@business-logic/types/CustomerDetails'; -import { EndorsementType } from '@business-logic/types/Enums'; +import { IEndorsementDetails } from 'safelite-playwright-core'; +import { EndorsementType } from 'safelite-playwright-core'; import { InsuranceBasePage } from './InsuranceBasePage'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; export class EndorsementsPage extends InsuranceBasePage { readonly page: Page; diff --git a/playwright-tests/pages/EstimatePage.ts b/playwright-tests/pages/EstimatePage.ts index 4eac6dc1f..deb494a92 100644 --- a/playwright-tests/pages/EstimatePage.ts +++ b/playwright-tests/pages/EstimatePage.ts @@ -1,12 +1,13 @@ import { type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { ProgressBarPercentages, VehicleLookupType } from '@business-logic/types/Enums'; -import { IVehicleDetails } from '@business-logic/types/CustomerDetails'; +import { VehicleLookupType } from 'safelite-playwright-core'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; +import { IVehicleDetails } from 'safelite-playwright-core'; import { VinLookupPage } from './VinLookupPage'; import { VehicleLookupAddressPage } from './VehicleLookupAddressPage'; import { VehicleLookupLicensePage } from './VehicleLookupLicensePage'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; export class EstimatePage extends BasePage { readonly page: Page; diff --git a/playwright-tests/pages/InsuranceCompanyPage.ts b/playwright-tests/pages/InsuranceCompanyPage.ts index 05b88f82a..48ae0b588 100644 --- a/playwright-tests/pages/InsuranceCompanyPage.ts +++ b/playwright-tests/pages/InsuranceCompanyPage.ts @@ -1,10 +1,8 @@ import { type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { IClaimDetails } from '@business-logic/types/CustomerDetails'; -import { step } from '@business-logic/types/Step'; -import TestCase from '@business-logic/types/TestCase'; -import { ITestData } from '@business-logic/types/ITestData'; -import { ProgressBarPercentages } from '@business-logic/types/Enums'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; export class InsuranceCompanyPage extends BasePage { diff --git a/playwright-tests/pages/LookupPage.ts b/playwright-tests/pages/LookupPage.ts index 06832cdb7..b964b3452 100644 --- a/playwright-tests/pages/LookupPage.ts +++ b/playwright-tests/pages/LookupPage.ts @@ -1,8 +1,7 @@ import { type Locator, type Page, expect } from '@playwright/test'; import { BasePage } from './BasePage'; -import TestSuccessAlert from '@business-logic/types/TestSuccessAlert'; -import IAlertFlags from '@business-logic/types/IAlertFlags'; -import { VehicleLookupType } from '@business-logic/types/Enums'; +import { IAlertFlags, TestSuccessAlert } from 'safelite-playwright-core'; +import { VehicleLookupType } from 'safelite-playwright-core'; export class LookupPage extends BasePage { protected serviceZipTextBox: Locator; diff --git a/playwright-tests/pages/MoldingQuestionsPage.ts b/playwright-tests/pages/MoldingQuestionsPage.ts index 1473234eb..4a64901ae 100644 --- a/playwright-tests/pages/MoldingQuestionsPage.ts +++ b/playwright-tests/pages/MoldingQuestionsPage.ts @@ -1,8 +1,8 @@ import { Page } from "@playwright/test"; import { PartQuestionsPage } from "./PartQuestionPage"; -import { step } from "@business-logic/types/Step"; -import { ITestData } from "@business-logic/types/ITestData"; -import { ProgressBarPercentages } from "@business-logic/types/Enums"; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; export default class MoldingQuestionsPage extends PartQuestionsPage { url = process.env['BASE_URL']! + '/fmg/?fmgPage=molding-questions'; diff --git a/playwright-tests/pages/OrderConfirmationPage.ts b/playwright-tests/pages/OrderConfirmationPage.ts index 74a5a49e1..4b06f81ae 100644 --- a/playwright-tests/pages/OrderConfirmationPage.ts +++ b/playwright-tests/pages/OrderConfirmationPage.ts @@ -1,10 +1,12 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { test } from '@business-logic/types/Test'; -import { ICustomerDetails, IVehicleDetails } from '@business-logic/types/CustomerDetails'; -import { ServicePackage, PaymentType, PaymentMethod, AppointmentType, ProgressBarPercentages } from '@business-logic/types/Enums'; -import { ITestData } from '@business-logic/types/ITestData'; -import { step } from '@business-logic/types/Step'; +import { getTestObject } from 'framework/Typedefs'; +import { ServicePackage, PaymentType, ServiceLocation } from 'safelite-playwright-core'; +import { PaymentMethod, ProgressBarPercentages } from "framework/localTypes/Enums"; +import { ITestData } from 'framework/TestData'; +import { step } from 'framework/localTypes/Step'; + +const test = getTestObject(); export class OrderConfirmationPage extends BasePage { readonly page: Page; @@ -43,8 +45,8 @@ export class OrderConfirmationPage extends BasePage { async validateOrderConfirmationPage(testData: Partial) { // Destructure data we use - const { vehicleDetails, customerDetails, servicePackage, promoCode, - isPolicyFound, claimDetails, paymentDetails, isUseVehicleOnPolicy, paymentMethod } = testData; + const { vehicleDetails, customerDetails, servicePackage, + paymentDetails, paymentMethod } = testData; await this.serviceText.waitFor({ state: "visible" }); expect.soft((await this.getActualAppointmentSummary()).map(item => item.toLowerCase())).toEqual((await this.getExpectedAppointmentSummary(testData)).map(item => item.toLowerCase())); @@ -73,8 +75,8 @@ export class OrderConfirmationPage extends BasePage { } // Promo Code Validation - if (promoCode) { - expect.soft(servicePackageValue).toContain(`Promo code ${promoCode} applied`); + if (paymentDetails!.promoCode) { + expect.soft(servicePackageValue).toContain(`Promo code ${paymentDetails!.promoCode} applied`); }; if (paymentMethod === PaymentMethod.SelfPay || (paymentDetails?.paymentType && paymentDetails?.paymentType !== PaymentType.PayWithInsurance)) { @@ -156,15 +158,15 @@ export class OrderConfirmationPage extends BasePage { // Format the expected appointment date const formattedExpectedAppointmentDate = await this.getFormattedAppointmentDate(customerDetails!.apptDate!); appointmentSummary.push( - appointmentDetails?.serviceLocation == AppointmentType.Mobile + appointmentDetails?.serviceLocation == ServiceLocation.Mobile ? formattedExpectedAppointmentDate + `${customerDetails!.apptTime?.replace("arriving between", "Between").replaceAll(":00", "")}` - : appointmentDetails?.serviceLocation == AppointmentType.InShop + : appointmentDetails?.serviceLocation == ServiceLocation.InShop ? formattedExpectedAppointmentDate + `${customerDetails!.apptTime}` : formattedExpectedAppointmentDate + "Drop off before 9:30 AM" ); appointmentSummary.push("Add to calendar"); appointmentSummary.push( - appointmentDetails?.serviceLocation == AppointmentType.Mobile + appointmentDetails?.serviceLocation == ServiceLocation.Mobile ? appointmentDetails?.serviceAddress ? ("We're coming to you at" + appointmentDetails.serviceAddress.street + ", " + appointmentDetails.serviceAddress.city + ", " + appointmentDetails.serviceAddress.state + " " + appointmentDetails.serviceAddress.postalCode + "to service your " + `${vehicleDetails!.year} ${vehicleDetails!.make} ${vehicleDetails!.model}`) : "" diff --git a/playwright-tests/pages/PartQuestionPage.ts b/playwright-tests/pages/PartQuestionPage.ts index 46b4b2440..756366cb3 100644 --- a/playwright-tests/pages/PartQuestionPage.ts +++ b/playwright-tests/pages/PartQuestionPage.ts @@ -1,9 +1,9 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { IPartQuestion } from '@business-logic/types/CustomerDetails'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; -import { ProgressBarPercentages } from '@business-logic/types/Enums'; +import { IPartQuestion } from 'safelite-playwright-core'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; export class PartQuestionsPage extends BasePage { readonly page: Page; diff --git a/playwright-tests/pages/PaymentMethodPage.ts b/playwright-tests/pages/PaymentMethodPage.ts index 240d0e03e..ce81a7462 100644 --- a/playwright-tests/pages/PaymentMethodPage.ts +++ b/playwright-tests/pages/PaymentMethodPage.ts @@ -1,12 +1,13 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { IPaymentDetails } from '@business-logic/types/CustomerDetails'; -import { AppointmentTimeslot, AppointmentType, PaymentMethod, PaymentType, ProgressBarPercentages, ServicePackage, VehicleDamage } from '@business-logic/types/Enums'; +import { IPaymentDetails } from 'safelite-playwright-core'; +import { AppointmentTimeslot, ServiceLocation, PaymentType, ServicePackage, VehicleDamage } from 'safelite-playwright-core'; +import { PaymentMethod, ProgressBarPercentages } from 'framework/localTypes/Enums'; import { PaymentPage } from './PaymentPage'; import { AfterpayPage } from './AfterpayPage'; import { PaypalPage } from './PaypalPage'; -import { ITestData } from '@business-logic/types/ITestData'; -import { step } from '@business-logic/types/Step'; +import { ITestData } from 'framework/TestData'; +import { step } from 'framework/localTypes/Step'; export class PaymentMethodPage extends BasePage { readonly page: Page; @@ -85,8 +86,8 @@ export class PaymentMethodPage extends BasePage { async validatePaymentDetailsPage(testData: Partial) { // Destructure data we use - const { vehicleDetails, customerDetails, servicePackage, promoCode, - isPolicyFound, claimDetails, paymentDetails, appointmentDetails, + const { vehicleDetails, customerDetails, servicePackage, + flow, claimDetails, paymentDetails, appointmentDetails, isUseVehicleOnPolicy, paymentMethod, vehicleDamage } = testData; // Wait for review table to be visible to ensure page is loaded @@ -152,8 +153,8 @@ export class PaymentMethodPage extends BasePage { } // Promo Code Validation - if (promoCode) { - expect.soft(servicePackageValue).toContain(`Promo code ${promoCode} applied`); + if (paymentDetails!.promoCode) { + expect.soft(servicePackageValue).toContain(`Promo code ${paymentDetails!.promoCode} applied`); }; // Early Bird line item validation @@ -395,13 +396,13 @@ l async getExpectedServiceLocation(testData: Partial, expectedServicePackageDetails: Map): Promise { const { appointmentDetails } = testData; - let serviceLocationTitle = appointmentDetails?.serviceLocation == AppointmentType.Mobile + let serviceLocationTitle = appointmentDetails?.serviceLocation == ServiceLocation.Mobile ? "We're coming to you" : "You're going to a Safelite shop"; let serviceLocation: string[] = []; serviceLocation.push( - appointmentDetails?.serviceLocation == AppointmentType.Mobile + appointmentDetails?.serviceLocation == ServiceLocation.Mobile ? appointmentDetails?.serviceAddress ? appointmentDetails.serviceAddress.street + ", " + appointmentDetails.serviceAddress.city + ", " + appointmentDetails.serviceAddress.state + " " + appointmentDetails.serviceAddress.postalCode : "" @@ -417,7 +418,7 @@ l async getExpectedAppointmentDate(testData: Partial, expectedServicePackageDetails: Map): Promise { const { customerDetails, appointmentDetails } = testData; let appointmentDateText: string[] = []; - const isMobileAppointment = appointmentDetails?.serviceLocation == AppointmentType.Mobile + const isMobileAppointment = appointmentDetails?.serviceLocation == ServiceLocation.Mobile if (isMobileAppointment) { let localStorage= JSON.parse(await this.page.evaluate('localStorage.getItem(\'vuex\')')); let jobMinMinutes = localStorage.order.schedule.jobMinMinutes as number; diff --git a/playwright-tests/pages/PaymentPage.ts b/playwright-tests/pages/PaymentPage.ts index e18311b08..9c69cb96b 100644 --- a/playwright-tests/pages/PaymentPage.ts +++ b/playwright-tests/pages/PaymentPage.ts @@ -1,6 +1,6 @@ import { type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { IPaymentDetails } from '@business-logic/types/CustomerDetails'; +import { IPaymentDetails } from 'safelite-playwright-core'; export class PaymentPage extends BasePage { readonly page: Page; diff --git a/playwright-tests/pages/PaypalPage.ts b/playwright-tests/pages/PaypalPage.ts index 4d957eb33..07e2cd1e6 100644 --- a/playwright-tests/pages/PaypalPage.ts +++ b/playwright-tests/pages/PaypalPage.ts @@ -1,6 +1,6 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { IPaymentDetails } from '@business-logic/types/CustomerDetails'; +import { IPaymentDetails } from 'safelite-playwright-core'; export class PaypalPage extends BasePage { readonly page: Page; diff --git a/playwright-tests/pages/PolicyDriverPage.ts b/playwright-tests/pages/PolicyDriverPage.ts index 1bb140088..94bd9db19 100644 --- a/playwright-tests/pages/PolicyDriverPage.ts +++ b/playwright-tests/pages/PolicyDriverPage.ts @@ -1,8 +1,8 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { InsuranceBasePage } from './InsuranceBasePage'; -import { ICustomerDetails } from '@business-logic/types/CustomerDetails'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; +import { ICustomerDetails } from 'safelite-playwright-core'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; export class PolicyDriverPage extends InsuranceBasePage { readonly page: Page; diff --git a/playwright-tests/pages/PolicyInfoSubmittedPage.ts b/playwright-tests/pages/PolicyInfoSubmittedPage.ts index 0a4bf79be..7d7d7f009 100644 --- a/playwright-tests/pages/PolicyInfoSubmittedPage.ts +++ b/playwright-tests/pages/PolicyInfoSubmittedPage.ts @@ -1,6 +1,6 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { InsuranceBasePage } from './InsuranceBasePage'; -import { step } from '@business-logic/types/Step'; +import { step } from 'framework/localTypes/Step'; export class PolicyInfoSubmittedPage extends InsuranceBasePage { readonly page: Page; diff --git a/playwright-tests/pages/PolicyVehiclesPage.ts b/playwright-tests/pages/PolicyVehiclesPage.ts index 67776adf6..bd749e056 100644 --- a/playwright-tests/pages/PolicyVehiclesPage.ts +++ b/playwright-tests/pages/PolicyVehiclesPage.ts @@ -1,8 +1,8 @@ import { expect, type Locator, type Page } from '@playwright/test'; -import { IVehicleDetails } from '@business-logic/types/CustomerDetails'; +import { IVehicleDetails } from 'safelite-playwright-core'; import { InsuranceBasePage } from './InsuranceBasePage'; -import { ITestData } from '@business-logic/types/ITestData'; -import { step } from '@business-logic/types/Step'; +import { ITestData } from 'framework/TestData'; +import { step } from 'framework/localTypes/Step'; export class PolicyVehiclesPage extends InsuranceBasePage { readonly page: Page; diff --git a/playwright-tests/pages/RecalibrationInfoPage.ts b/playwright-tests/pages/RecalibrationInfoPage.ts index 7310d6c16..493714a66 100644 --- a/playwright-tests/pages/RecalibrationInfoPage.ts +++ b/playwright-tests/pages/RecalibrationInfoPage.ts @@ -1,6 +1,6 @@ import { Locator, Page } from "@playwright/test"; import { InsuranceBasePage } from "./InsuranceBasePage"; -import { step } from "@business-logic/types/Step"; +import { step } from 'framework/localTypes/Step'; export default class RecalibrationInfoPage extends InsuranceBasePage { url = process.env['BASE_URL']! + '/FixMyGlass/RecalibrationInfo.aspx'; diff --git a/playwright-tests/pages/SchedulePage.ts b/playwright-tests/pages/SchedulePage.ts index 5fdcf5ce3..7f960c2c0 100644 --- a/playwright-tests/pages/SchedulePage.ts +++ b/playwright-tests/pages/SchedulePage.ts @@ -1,11 +1,12 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { IAppointmentDetails, ICustomerDetails } from '@business-logic/types/CustomerDetails'; -import { formatDate, formatTime } from '@impl/utils/DateUtils'; -import { AppointmentTimeslot, AppointmentType, ProgressBarPercentages, ServiceLocation } from '@business-logic/types/Enums'; +import { IAppointmentDetails } from 'safelite-playwright-core'; +import { formatDate, formatTime } from 'safelite-playwright-core'; +import { AppointmentTimeslot } from 'safelite-playwright-core'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; import { time } from 'console'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; export class SchedulePage extends BasePage { readonly page: Page; @@ -78,7 +79,7 @@ export class SchedulePage extends BasePage { }); } - // appointmentmentDetails.serviceLocation === AppointmentType.DropOff ? await this.dropOffButton.click() : await this.firstAvailableTime.click(); + // appointmentmentDetails.serviceLocation === ServiceLocation.DropOff ? await this.dropOffButton.click() : await this.firstAvailableTime.click(); customerDetails!.apptDuration = (await this.appointmentDuration.innerText()).replace("Duration: ", ""); await this.nextPage(); } diff --git a/playwright-tests/pages/ServiceLocationPage.ts b/playwright-tests/pages/ServiceLocationPage.ts index 747534501..e7af1a4ba 100644 --- a/playwright-tests/pages/ServiceLocationPage.ts +++ b/playwright-tests/pages/ServiceLocationPage.ts @@ -1,11 +1,12 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { IAppointmentDetails } from '@business-logic/types/CustomerDetails'; -import { AppointmentTimeslot, AppointmentType, ProgressBarPercentages } from '@business-logic/types/Enums'; +import { IAppointmentDetails } from 'safelite-playwright-core'; +import { AppointmentTimeslot, ServiceLocation } from 'safelite-playwright-core'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; import { AddressForm } from './forms/AddressForm'; import { faker } from '@faker-js/faker'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; export class ServiceLocationPage extends BasePage { readonly page: Page; @@ -78,13 +79,13 @@ export class ServiceLocationPage extends BasePage { const { appointmentDetails, customerDetails } = testData; switch(appointmentDetails?.serviceLocation) { - case AppointmentType.Mobile: + case ServiceLocation.Mobile: await this.scheduleMobile(testData); break; - case AppointmentType.InShop: + case ServiceLocation.InShop: await this.scheduleInShop(appointmentDetails); break; - case AppointmentType.DropOff: + case ServiceLocation.DropOff: await this.scheduleDropOff(appointmentDetails); break; } diff --git a/playwright-tests/pages/ServicePackagesPage.ts b/playwright-tests/pages/ServicePackagesPage.ts index e670ff31b..27e780e53 100644 --- a/playwright-tests/pages/ServicePackagesPage.ts +++ b/playwright-tests/pages/ServicePackagesPage.ts @@ -1,9 +1,10 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { BasePage } from './BasePage'; -import { ProgressBarPercentages, ServicePackage, VehicleDamage } from '@business-logic/types/Enums'; -import { PaymentMethod } from '@business-logic/types/Enums'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; +import { ServicePackage, VehicleDamage } from 'safelite-playwright-core'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; +import { PaymentMethod } from "framework/localTypes/Enums"; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; export class ServicePackagesPage extends BasePage { readonly page: Page; @@ -183,7 +184,7 @@ export class ServicePackagesPage extends BasePage { @step("ServicePackagePage >> Select Payment Method and Service Type: ") async handleServicePackagePage(testData: Partial) { - const { customerDetails, paymentMethod, servicePackage, promoCode, canNotRecal, dynamicRecal, hasOemEndorsement, vehicleDamage } = testData; + const { customerDetails, paymentMethod, paymentDetails, servicePackage, isCanNotRecal, isDynamicRecal, hasOemEndorsement, vehicleDamage } = testData; await this.validateProgressBar(ProgressBarPercentages.ServicePackagePage); // Define repair damage types (vs. replacement types) @@ -203,18 +204,18 @@ export class ServicePackagesPage extends BasePage { await this.selectServicePackage(servicePackage!); // Enter promo code - if (promoCode) { - await this.enterPromo(promoCode); + if (paymentDetails?.promoCode) { + await this.enterPromo(paymentDetails.promoCode); } // Backend Validations // Validate backend for can not recal if applicable - if (canNotRecal) { + if (isCanNotRecal) { await this.verifyCanNotRecal(); } // Validate backend for dynamic recal if applicable - if (dynamicRecal) { + if (isDynamicRecal) { await this.verifyDynamicRecal(); } diff --git a/playwright-tests/pages/ServiceZipPage.ts b/playwright-tests/pages/ServiceZipPage.ts index eb2d901cf..dec4a8c44 100644 --- a/playwright-tests/pages/ServiceZipPage.ts +++ b/playwright-tests/pages/ServiceZipPage.ts @@ -1,8 +1,8 @@ import { Page } from "@playwright/test"; import { LookupPage } from "./LookupPage"; -import { step } from "@business-logic/types/Step"; -import { ITestData } from "@business-logic/types/ITestData"; -import { ProgressBarPercentages } from "@business-logic/types/Enums"; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; export class ServiceZipPage extends LookupPage { diff --git a/playwright-tests/pages/VehicleDamagePage.ts b/playwright-tests/pages/VehicleDamagePage.ts index da83d63fc..6f2f61c2c 100644 --- a/playwright-tests/pages/VehicleDamagePage.ts +++ b/playwright-tests/pages/VehicleDamagePage.ts @@ -1,9 +1,10 @@ import { type Locator, type Page, expect, test } from '@playwright/test'; import { BasePage } from './BasePage'; -import { ProgressBarPercentages, SideDoorDamage, VehicleDamage, WindshieldDamage } from '@business-logic/types/Enums'; -import TestSuccessAlert from '@business-logic/types/TestSuccessAlert'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; +import { VehicleDamage } from 'safelite-playwright-core'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; +import { TestSuccessAlert } from 'safelite-playwright-core'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; export class VehicleDamagePage extends BasePage { readonly page: Page; diff --git a/playwright-tests/pages/VehicleLookupAddressPage.ts b/playwright-tests/pages/VehicleLookupAddressPage.ts index d21edebbf..c3835131c 100644 --- a/playwright-tests/pages/VehicleLookupAddressPage.ts +++ b/playwright-tests/pages/VehicleLookupAddressPage.ts @@ -2,10 +2,10 @@ import { type Page, Locator } from '@playwright/test'; import { LookupPage } from './LookupPage'; import { AddressForm } from './forms/AddressForm'; import { VehicleSelectionForm } from './forms/VehicleSelectionForm'; -import { ICustomerDetails, IVehicleDetails } from '@business-logic/types/CustomerDetails'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; -import { ProgressBarPercentages } from '@business-logic/types/Enums'; +import { ICustomerDetails, IVehicleDetails } from 'safelite-playwright-core'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; export class VehicleLookupAddressPage extends LookupPage { readonly addressForm: AddressForm; diff --git a/playwright-tests/pages/VehicleLookupLicensePage.ts b/playwright-tests/pages/VehicleLookupLicensePage.ts index 3aea24670..3ed9e33c5 100644 --- a/playwright-tests/pages/VehicleLookupLicensePage.ts +++ b/playwright-tests/pages/VehicleLookupLicensePage.ts @@ -1,9 +1,9 @@ import { type Locator, type Page } from '@playwright/test'; import { LookupPage } from './LookupPage'; -import { IVehicleDetails } from '@business-logic/types/CustomerDetails'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; -import { ProgressBarPercentages } from '@business-logic/types/Enums'; +import { IVehicleDetails } from 'safelite-playwright-core'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; export class VehicleLookupLicensePage extends LookupPage { readonly licensePlateNumTextBox: Locator; @@ -25,7 +25,13 @@ export class VehicleLookupLicensePage extends LookupPage { } async enterPlateDetails(vehicleDetails: IVehicleDetails) { - await this.licensePlateNumTextBox.fill(vehicleDetails.licensePlateNumber || ''); + let licensePlateNumber: string; + if (Array.isArray(vehicleDetails.licensePlate)) { + licensePlateNumber = vehicleDetails.licensePlate[0].licensePlateNumber; + } else { + licensePlateNumber = vehicleDetails.licensePlate?.licensePlateNumber || ''; + } + await this.licensePlateNumTextBox.fill(licensePlateNumber); } @step("VehicleLookupLicensePage >> Lookup by license plate: ") diff --git a/playwright-tests/pages/VehiclePartsPage.ts b/playwright-tests/pages/VehiclePartsPage.ts index 4bb801481..ddea1f5f8 100644 --- a/playwright-tests/pages/VehiclePartsPage.ts +++ b/playwright-tests/pages/VehiclePartsPage.ts @@ -1,8 +1,8 @@ import { Page } from "@playwright/test"; import { PartQuestionsPage } from "./PartQuestionPage"; -import { step } from "@business-logic/types/Step"; -import { ITestData } from "@business-logic/types/ITestData"; -import { ProgressBarPercentages } from "@business-logic/types/Enums"; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; export default class VehiclePartQuestionsPage extends PartQuestionsPage{ url = process.env['BASE_URL']! + '/fmg/?fmgPage=vehicle-parts'; diff --git a/playwright-tests/pages/VehicleSelectionPage.ts b/playwright-tests/pages/VehicleSelectionPage.ts index 38eaf5e63..5dcd7fd25 100644 --- a/playwright-tests/pages/VehicleSelectionPage.ts +++ b/playwright-tests/pages/VehicleSelectionPage.ts @@ -1,10 +1,10 @@ import { type Locator, type Page, expect, test } from '@playwright/test'; import { BasePage } from './BasePage'; -import { IVehicleDetails } from '@business-logic/types/CustomerDetails'; -import TestSuccessAlert from '@business-logic/types/TestSuccessAlert'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; -import { ProgressBarPercentages } from '@business-logic/types/Enums'; +import { IVehicleDetails } from 'safelite-playwright-core'; +import { TestSuccessAlert } from 'safelite-playwright-core'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; export class VehicleSelectionPage extends BasePage { readonly page: Page; diff --git a/playwright-tests/pages/VerifyDetailsPage.ts b/playwright-tests/pages/VerifyDetailsPage.ts index 212ed7968..cf8cbeba4 100644 --- a/playwright-tests/pages/VerifyDetailsPage.ts +++ b/playwright-tests/pages/VerifyDetailsPage.ts @@ -1,8 +1,8 @@ import { expect, type Locator, type Page } from '@playwright/test'; -import { IClaimDetails, ICustomerDetails } from '@business-logic/types/CustomerDetails'; +import { IClaimDetails, ICustomerDetails } from 'safelite-playwright-core'; import { InsuranceBasePage } from './InsuranceBasePage'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; export class VerifyDetailsPage extends InsuranceBasePage { readonly page: Page; diff --git a/playwright-tests/pages/VinLookupPage.ts b/playwright-tests/pages/VinLookupPage.ts index 52f156c17..ae3ce3f21 100644 --- a/playwright-tests/pages/VinLookupPage.ts +++ b/playwright-tests/pages/VinLookupPage.ts @@ -1,8 +1,8 @@ import { type Locator, type Page } from '@playwright/test'; import { LookupPage } from './LookupPage'; -import { step } from '@business-logic/types/Step'; -import { ITestData } from '@business-logic/types/ITestData'; -import { ProgressBarPercentages } from '@business-logic/types/Enums'; +import { step } from 'framework/localTypes/Step'; +import { ITestData } from 'framework/TestData'; +import { ProgressBarPercentages } from 'framework/localTypes/Enums'; export class VinLookupPage extends LookupPage { readonly vinLookupTextBox: Locator; @@ -27,9 +27,16 @@ export class VinLookupPage extends LookupPage { @step("VinLookupPage >> Lookup by VIN: ") async handleVehicleLookupVinPage(testData: Partial) { const { customerDetails, vehicleDetails, alertFlags } = testData; + let vin: string; + + if (Array.isArray(vehicleDetails?.vin)) { + vin = vehicleDetails.vin[0]; + } else { + vin = vehicleDetails?.vin || ''; + } await this.validateProgressBar(ProgressBarPercentages.VinLookupPage); - await this.enterVin(vehicleDetails!.vin!); + await this.enterVin(vin); await this.enterZip(customerDetails!.address.postalCode!); await this.handleZipValidation(customerDetails!.address.postalCode!, vehicleDetails!.vehicleLookupType!, alertFlags!); } diff --git a/playwright-tests/pages/forms/AddressForm.ts b/playwright-tests/pages/forms/AddressForm.ts index 892a56c9b..4ddb6a512 100644 --- a/playwright-tests/pages/forms/AddressForm.ts +++ b/playwright-tests/pages/forms/AddressForm.ts @@ -1,7 +1,7 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { BasePage } from '../BasePage'; -import { ICustomerDetails } from '@business-logic/types/CustomerDetails'; -import { waitUntil } from '@impl/utils/TimingUtils'; +import { ICustomerDetails } from 'safelite-playwright-core'; +import { waitUntil } from 'safelite-playwright-core'; export class AddressForm extends BasePage { readonly page: Page; diff --git a/playwright-tests/pages/forms/VehicleSelectionForm.ts b/playwright-tests/pages/forms/VehicleSelectionForm.ts index e9125cfd5..361e42cf3 100644 --- a/playwright-tests/pages/forms/VehicleSelectionForm.ts +++ b/playwright-tests/pages/forms/VehicleSelectionForm.ts @@ -1,6 +1,6 @@ import { type Page } from '@playwright/test'; import { BasePage } from '../BasePage'; -import { IVehicleDetails } from '@business-logic/types/CustomerDetails'; +import { IVehicleDetails } from 'safelite-playwright-core'; export class VehicleSelectionForm extends BasePage { readonly page: Page; diff --git a/playwright-tests/playwright.config.ts b/playwright-tests/playwright.config.ts index 8e4b1da2a..90a7183eb 100644 --- a/playwright-tests/playwright.config.ts +++ b/playwright-tests/playwright.config.ts @@ -1,4 +1,4 @@ -import { formatDateForFilename } from '@impl/utils/DateUtils'; +import { formatDateForFilename } from 'safelite-playwright-core'; import { defineConfig, devices } from '@playwright/test'; import { JiraReporterConfig } from 'playwright-jira-reporter' import dotenv from 'dotenv-safe'; @@ -38,7 +38,6 @@ if (!process.env.CI) { const ortoniReportConfig: OrtoniReportConfig = { open: "never", folderPath: 'playwright-tests/test-results', - logo: "../business-logic/data/logo.png", title: "Test Report", filename: `ortoni_report_${formatDateForFilename(new Date())}.html`, showProject: false, diff --git a/playwright-tests/tests/0000__M.test.ts b/playwright-tests/tests/0000__M.test.ts index b51c8dd5e..7d1d44829 100644 --- a/playwright-tests/tests/0000__M.test.ts +++ b/playwright-tests/tests/0000__M.test.ts @@ -1,7 +1,6 @@ -import TestCase from "@business-logic/types/TestCase"; import { Page } from "@playwright/test"; -import { addSmokeTagToRandomTest, prepareTest, test, TestInfo } from "@business-logic/types/Test"; -import { RuleEngine, ValidationOptions } from "@business-logic/types/RuleEngine"; +import { addSmokeTagToRandomTest, Flow } from 'safelite-playwright-core'; +import { ValidationOptions } from 'safelite-playwright-core'; import heavyTruckTests from "./alert-validation/alert0001_HeavyTruck"; import repairAndReplaceTests from "./alert-validation/alert0002_RepairAndReplace"; import splitWindshieldTests from "./alert-validation/alert0003_SplitWindshield"; @@ -9,13 +8,14 @@ import repairOnlyTests from "./alert-validation/alert0004_RepairOnly"; import unserviceableZipTests from "./alert-validation/alert0005_UnserviceableZip"; import invalidZipTests from "./alert-validation/alert0006_InvalidZip"; import vinNotFoundTests from "./alert-validation/alert0007_VinNotFound"; -import TestSuccessAlert from "@business-logic/types/TestSuccessAlert"; -import { AppointmentType, PaymentMethod, ServicePackage, VehicleLookupType, VehicleDamage, PaymentType } from "@business-logic/types/Enums"; +import { TestSuccessAlert } from 'safelite-playwright-core'; +import { VehicleLookupType, VehicleDamage, PaymentType } from 'safelite-playwright-core'; +import { PaymentMethod } from "framework/localTypes/Enums"; import cashRepairMobileCCTests from "./CashRepairMobileCreditCard"; import cashReplaceDynamicRecalMobileTests from "./CashReplaceDynamicRecalMobile"; import cashReplaceGlassAddressLookupInshopAfterPayTests from "./CashReplaceGlassAddressLookupInshopAfterPay"; import cashReplaceGlassLicensePlateLookupInshopPaypalTests from "./CashReplaceGlassLicensePlateLookupInshopPaypal"; -import ApiResponseInterceptUtil from "@impl/API/ApiResponseInterceptUtil"; +import { ApiResponseInterceptUtil } from 'safelite-playwright-core'; import cashReplaceGlassPromoInshopTests from "./CashReplaceGlassPromoInshop"; import cashReplaceMultiGlassPromoInshopTests from "./CashReplaceMultiGlassPromoInshop"; import cashReplaceRainDefensePromoInshopTests from "./CashReplaceRainDefensePromoInshop"; @@ -31,6 +31,10 @@ import cashRepairInShopAfterPayTests from "./CashRepairInShopAfterPay"; import cashRepairInShopPayPalTests from "./CashRepairInShopPayPal"; import cashReplaceMultiSlidingGlassDropoffTests from "./CashReplaceMultiSlidingGlassDropoff"; import cashReplaceMultiGlassMobileTests from "./CashReplaceMultiGlassMobile"; +import { getTestObject, TestCase, prepareTest, RuleEngine, TestInfo } from 'framework/Typedefs'; +import { createTestPages } from "framework/TestPages"; + +const test = getTestObject(); /** * Master Test Runner @@ -41,7 +45,7 @@ import cashReplaceMultiGlassMobileTests from "./CashReplaceMultiGlassMobile"; */ // Initialize shared rule engine and validation options -const ruleEngine = new RuleEngine(); +const ruleEngine = new RuleEngine(); const options = new ValidationOptions(); // Add smoke tag to selected tests for CI/CD pipelines @@ -87,7 +91,7 @@ const allAlertTests = [ test.describe.parallel('Standard E2E Test Flows', () => { allStandardTests.forEach(scenario => { scenario.tests.forEach(testCase => { - test(...prepareTest(testCase, run, options, ruleEngine)); + test(...prepareTest(testCase, createTestPages, run, options, ruleEngine)); }); }); }); @@ -97,7 +101,7 @@ test.describe.parallel('Alert Validation Tests', () => { allAlertTests.forEach(scenario => { test.describe(scenario.name, () => { scenario.tests.forEach(testCase => { - test(...prepareTest(testCase, run, options, ruleEngine)); + test(...prepareTest(testCase, createTestPages, run, options, ruleEngine)); }); }); }); @@ -119,7 +123,7 @@ test.afterEach(async ({ page, testInfo }) => { async function run(page: Page, testInfo: TestInfo): Promise { try { await testInfo.testCase.setup(); - testInfo.testCase.setupPages(page); + testInfo.testCase.setupPages(page, createTestPages); await testInfo.testCase.pages.homePage.goto(); await runWorkflow(page, testInfo.testCase); } catch (error) { @@ -157,8 +161,8 @@ async function runWorkflow(page: Page, testCase: TestCase) { // Destructure test data for easier access const { paymentMethod, customerDetails, vehicleDetails, vehicleDamage, - paymentDetails, partQuestions, enterFunnelWithZip, capabilityQuestions, - vehiclePartQuestions, moldingQuestions, skipEstimatePage + paymentDetails, partQuestions, isEnterFunnelWithZip, capabilityQuestions, + vehiclePartQuestions, moldingQuestions, isSkipEstimatePage } = testCase.testData; // Check if the vehicle damage includes a windshield crack @@ -173,11 +177,11 @@ async function runWorkflow(page: Page, testCase: TestCase) { await test.step('HomePage >> Lets Get Started', async () => { let homePage = testCase.pages.homePage; console.log(`Customer for this test: ${customerDetails?.firstName} ${customerDetails?.lastName}`); - await homePage.letsGetStarted(customerDetails?.address.postalCode!, !!enterFunnelWithZip!); + await homePage.letsGetStarted(customerDetails?.address.postalCode!, !!isEnterFunnelWithZip!); }); } else { // If enterFunnelWithZip is true, add zip code to url - if (!!enterFunnelWithZip!) { + if (!!isEnterFunnelWithZip!) { const currentUrl = page.url(); const zipParam = `&zipCode=${customerDetails?.address.postalCode!}`; if (!currentUrl.includes('zipCode=')) { @@ -196,7 +200,7 @@ async function runWorkflow(page: Page, testCase: TestCase) { await vehicleDamagePage.handleVehicleDamagePage(testCase.testData); // If the vehicle has a windshield crack as part of its damage, go to estimate page and select lookup type - if (hasWindshieldCrack && !skipEstimatePage) { + if (hasWindshieldCrack && !isSkipEstimatePage) { let estimatePage = testCase.pages.estimatePage; await estimatePage.handleEstimatePage(testCase.testData); @@ -296,7 +300,7 @@ async function runWorkflow(page: Page, testCase: TestCase) { } export async function handleInsuranceFlow(testCase: TestCase) { - const { isPolicyFound, isPolicyDriver, endorsements, isRecalNotification } = testCase.testData; + const { flow, isPolicyDriver, endorsements, isRecalNotification } = testCase.testData; // Check if the insurance policy has endorsements const hasEndorsements = endorsements && endorsements.length > 0; @@ -314,7 +318,7 @@ export async function handleInsuranceFlow(testCase: TestCase) { await duplicateCheckPage.handleDuplicateCheckPage(testCase.testData); } - if (isPolicyFound) { + if ( flow === Flow.Managed ) { let policyVehiclesPage = testCase.pages.policyVehiclesPage; await policyVehiclesPage.handlePolicyVehiclesPage(testCase.testData); diff --git a/playwright-tests/tests/CashRepairInShopAfterPay.ts b/playwright-tests/tests/CashRepairInShopAfterPay.ts index c3954db9f..edb811ea5 100644 --- a/playwright-tests/tests/CashRepairInShopAfterPay.ts +++ b/playwright-tests/tests/CashRepairInShopAfterPay.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { VehicleDamage, AppointmentType, ServicePackage } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import PaymentData from "@business-logic/Data/PaymentData"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { VehicleDamage, ServiceLocation, ServicePackage } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { ClientData } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed before generating any data setFakerSeedFromTestName("CashRepairInShopAfterPay"); @@ -31,16 +31,16 @@ const cashRepairInShopAfterPayData : Partial = { }, // Use predefined payment data - paymentDetails: PaymentData.getDefaultAfterpayDetails() + paymentDetails: ClientData.getDefaultAfterpayDetails() } -const cashRepairInShopAfterPayTests: TestCase[] = []; +const cashRepairInShopAfterPayTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashRepairInShopAfterPay`, tags: ['@E2E','@CashRepairInShopAfterPay', '@test_report', '@CASH'], testData: cashRepairInShopAfterPayData -}, undefined, 'CashRepairInShopAfterPay'); +}; cashRepairInShopAfterPayTests.push(tc); export default cashRepairInShopAfterPayTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashRepairInShopPayPal.ts b/playwright-tests/tests/CashRepairInShopPayPal.ts index e17bcaed1..024d79c41 100644 --- a/playwright-tests/tests/CashRepairInShopPayPal.ts +++ b/playwright-tests/tests/CashRepairInShopPayPal.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { VehicleDamage, ServicePackage } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import PaymentData from "@business-logic/Data/PaymentData"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { VehicleDamage, ServicePackage } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { ClientData } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed before generating any data setFakerSeedFromTestName("CashRepairInShopPayPal"); @@ -31,16 +31,16 @@ const cashRepairInShopPayPalData : Partial = { }, // Use predefined payment data - paymentDetails: PaymentData.getDefaultPaypalDetails() + paymentDetails: ClientData.getDefaultPaypalDetails() } -const cashRepairInShopPayPalTests: TestCase[] = []; +const cashRepairInShopPayPalTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashRepairInShopPayPal`, tags: ['@E2E','@CashRepairInShopPayPal', '@test_report', '@CASH'], testData: cashRepairInShopPayPalData -}, undefined, 'CashRepairInShopPayPal'); +}; cashRepairInShopPayPalTests.push(tc); export default cashRepairInShopPayPalTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashRepairMobileCreditCard.ts b/playwright-tests/tests/CashRepairMobileCreditCard.ts index db8ebd8ce..c11771ea3 100644 --- a/playwright-tests/tests/CashRepairMobileCreditCard.ts +++ b/playwright-tests/tests/CashRepairMobileCreditCard.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { VehicleDamage, AppointmentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import PaymentData from "@business-logic/Data/PaymentData"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { VehicleDamage, ServiceLocation } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { ClientData } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed before generating any data setFakerSeedFromTestName("CashRepairMobileCreditCard"); @@ -32,7 +32,7 @@ const cashRepairMobileCCData : Partial = { // Override appointment details appointmentDetails: { - serviceLocation: AppointmentType.Mobile, + serviceLocation: ServiceLocation.Mobile, appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate, serviceAddress: { street: '13735 San Antonio Ave', @@ -44,16 +44,16 @@ const cashRepairMobileCCData : Partial = { }, // Use predefined payment data - paymentDetails: PaymentData.getDefaultCreditCardDetails() + paymentDetails: ClientData.getDefaultCreditCardDetails() } -const cashRepairMobileCCTests: TestCase[] = []; +const cashRepairMobileCCTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashRepairMobileCreditCard`, tags: ['@E2E','@CashRepairMobileCreditCard', '@test_report', '@CASH'], testData: cashRepairMobileCCData -}, undefined, 'CashRepairMobileCreditCard'); +}; cashRepairMobileCCTests.push(tc); export default cashRepairMobileCCTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashReplaceDynamicRecalMobile.ts b/playwright-tests/tests/CashReplaceDynamicRecalMobile.ts index 1f3d2e785..1818343d1 100644 --- a/playwright-tests/tests/CashReplaceDynamicRecalMobile.ts +++ b/playwright-tests/tests/CashReplaceDynamicRecalMobile.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { AppointmentType, PaymentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { ServiceLocation, PaymentType } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed before generating any data setFakerSeedFromTestName("CashReplaceDynamicRecalMobile"); @@ -16,7 +16,7 @@ const cashReplaceDynamicRecalMobileData: Partial = { isRecalVehicle: true, // Flag for dynamic Recalibration vehicle - dynamicRecal: true, + isDynamicRecal: true, customerDetails: { ...getDefaultTestData().customerDetails!, @@ -41,7 +41,7 @@ const cashReplaceDynamicRecalMobileData: Partial = { // Override appointment details appointmentDetails: { - serviceLocation: AppointmentType.Mobile, + serviceLocation: ServiceLocation.Mobile, appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate, serviceAddress: { // Use street address from current faker seed @@ -59,13 +59,13 @@ const cashReplaceDynamicRecalMobileData: Partial = { } } -const cashReplaceDynamicRecalMobileTests: TestCase[] = []; +const cashReplaceDynamicRecalMobileTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashReplaceDynamicRecalMobile`, tags: ['@E2E','@CashReplaceDynamicRecalMobile', '@test_report', '@CASH'], testData: cashReplaceDynamicRecalMobileData -}, undefined, 'CashReplaceDynamicRecalMobile'); +}; cashReplaceDynamicRecalMobileTests.push(tc); export default cashReplaceDynamicRecalMobileTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashReplaceGlassAddressLookupInshopAfterPay.ts b/playwright-tests/tests/CashReplaceGlassAddressLookupInshopAfterPay.ts index 34017c603..2c34b313f 100644 --- a/playwright-tests/tests/CashReplaceGlassAddressLookupInshopAfterPay.ts +++ b/playwright-tests/tests/CashReplaceGlassAddressLookupInshopAfterPay.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import PaymentData from "@business-logic/Data/PaymentData"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { ClientData } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed before generating any data setFakerSeedFromTestName("CashReplaceGlassAddressLookupInshopAfterPay"); @@ -13,7 +13,7 @@ const cashReplaceGlassAddressLookupInshopAfterPayData: Partial = { ...getDefaultTestData(), // Get default data with current seed // Enable entering funnel with ZIP - enterFunnelWithZip: true, + isEnterFunnelWithZip: true, // Override customer details customerDetails: { @@ -47,16 +47,16 @@ const cashReplaceGlassAddressLookupInshopAfterPayData: Partial = { }, // Override payment details - paymentDetails: PaymentData.getDefaultAfterpayDetails() + paymentDetails: ClientData.getDefaultAfterpayDetails() } -const cashReplaceGlassAddressLookupInshopAfterPayTests: TestCase[] = []; +const cashReplaceGlassAddressLookupInshopAfterPayTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashReplaceGlassAddressLookupInshopAfterPay`, tags: ['@E2E','@CashReplaceGlassAddressLookupInshopAfterPay', '@test_report', '@CASH'], testData: cashReplaceGlassAddressLookupInshopAfterPayData -}, undefined, 'CashReplaceGlassAddressLookupInshopAfterPay'); +}; cashReplaceGlassAddressLookupInshopAfterPayTests.push(tc); export default cashReplaceGlassAddressLookupInshopAfterPayTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashReplaceGlassLicensePlateLookupInshopPaypal.ts b/playwright-tests/tests/CashReplaceGlassLicensePlateLookupInshopPaypal.ts index d9b6d3afd..4499bb004 100644 --- a/playwright-tests/tests/CashReplaceGlassLicensePlateLookupInshopPaypal.ts +++ b/playwright-tests/tests/CashReplaceGlassLicensePlateLookupInshopPaypal.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import PaymentData from "@business-logic/Data/PaymentData"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { ClientData } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed before generating any data setFakerSeedFromTestName("CashReplaceGlassLicensePlateLookupInshopPaypal"); @@ -31,23 +31,23 @@ const cashReplaceGlassLicensePlateLookupInshopPaypalData: Partial = { make: 'Hyundai', model: 'Sonata', style: '4 door sedan', - licensePlateNumber: 'FTY 7776', + licensePlate: { licensePlateNumber: 'FTY 7776', licensePlateState: '' }, vehicleLookupType: VehicleLookupType.LicensePlateNumber }, // No need to override vehicleDamage as it already defaults to WindshieldCrack // Override payment details to use PayPal - paymentDetails: PaymentData.getDefaultPaypalDetails() + paymentDetails: ClientData.getDefaultPaypalDetails() } -const cashReplaceGlassLicensePlateLookupInshopPaypalTests: TestCase[] = []; +const cashReplaceGlassLicensePlateLookupInshopPaypalTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashReplaceGlassLicensePlateLookupInshopPaypal`, tags: ['@E2E','@CashReplaceGlassLicensePlateLookupInshopPaypal', '@test_report', '@CASH'], testData: cashReplaceGlassLicensePlateLookupInshopPaypalData -}, undefined, 'CashReplaceGlassLicensePlateLookupInshopPaypal'); +}; cashReplaceGlassLicensePlateLookupInshopPaypalTests.push(tc); export default cashReplaceGlassLicensePlateLookupInshopPaypalTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashReplaceGlassPromoInshop.ts b/playwright-tests/tests/CashReplaceGlassPromoInshop.ts index 900cebeff..0c4e44444 100644 --- a/playwright-tests/tests/CashReplaceGlassPromoInshop.ts +++ b/playwright-tests/tests/CashReplaceGlassPromoInshop.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { PaymentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { PaymentType } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed before generating any data setFakerSeedFromTestName("CashReplaceGlassPromoInshop"); @@ -12,9 +12,6 @@ setFakerSeedFromTestName("CashReplaceGlassPromoInshop"); const cashReplaceGlassPromoInshopData: Partial = { ...getDefaultTestData(), // Get default data with current seed - // Add promo code - key feature of this test - promoCode: '20CALL', - // Flag for recalibration vehicle isRecalVehicle: true, @@ -39,17 +36,19 @@ const cashReplaceGlassPromoInshopData: Partial = { // Override payment details paymentDetails: { - paymentType: PaymentType.PayAtService + paymentType: PaymentType.PayAtService, + // Add promo code - key feature of this test + promoCode: '20CALL', } } -const cashReplaceGlassPromoInshopTests: TestCase[] = []; +const cashReplaceGlassPromoInshopTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashReplaceGlassPromoInshop`, tags: ['@E2E','@CashReplaceGlassPromoInshop', '@test_report', '@CASH'], testData: cashReplaceGlassPromoInshopData -}, undefined, 'CashReplaceGlassPromoInshop'); +}; cashReplaceGlassPromoInshopTests.push(tc); export default cashReplaceGlassPromoInshopTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashReplaceMultiGlassMobile.ts b/playwright-tests/tests/CashReplaceMultiGlassMobile.ts index 2974d41d8..61bb84043 100644 --- a/playwright-tests/tests/CashReplaceMultiGlassMobile.ts +++ b/playwright-tests/tests/CashReplaceMultiGlassMobile.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { VehicleDamage, PartQuestionType, PaymentType, ServicePackage, AppointmentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { VehicleDamage, PartQuestionType, PaymentType, ServicePackage, ServiceLocation } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed before generating any data setFakerSeedFromTestName("CashReplaceMultiGlassMobile"); @@ -29,7 +29,7 @@ const cashReplaceMultiGlassMobileData: Partial = { // Override appointment details appointmentDetails: { - serviceLocation: AppointmentType.Mobile, + serviceLocation: ServiceLocation.Mobile, appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate, serviceAddress: { // Use street address from current faker seed @@ -87,13 +87,13 @@ const cashReplaceMultiGlassMobileData: Partial = { ] } -const cashReplaceMultiGlassMobileTests: TestCase[] = []; +const cashReplaceMultiGlassMobileTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashReplaceMultiGlassMobile`, tags: ['@E2E','@CashReplaceMultiGlassMobile', '@test_report', '@CASH'], testData: cashReplaceMultiGlassMobileData -}, undefined, 'CashReplaceMultiGlassMobile'); +}; cashReplaceMultiGlassMobileTests.push(tc); export default cashReplaceMultiGlassMobileTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashReplaceMultiGlassPromoInshop.ts b/playwright-tests/tests/CashReplaceMultiGlassPromoInshop.ts index 9682685ef..3d51dfbf6 100644 --- a/playwright-tests/tests/CashReplaceMultiGlassPromoInshop.ts +++ b/playwright-tests/tests/CashReplaceMultiGlassPromoInshop.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { VehicleDamage, PartQuestionType, PaymentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { VehicleDamage, PartQuestionType, PaymentType } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed before generating any data setFakerSeedFromTestName("CashReplaceMultiGlassPromoInshop"); @@ -12,9 +12,6 @@ setFakerSeedFromTestName("CashReplaceMultiGlassPromoInshop"); const cashReplaceMultiGlassPromoInshopData: Partial = { ...getDefaultTestData(), // Get default data with current seed - // Add promo code - promoCode: '20CALL', - // Flag for recalibration vehicle isRecalVehicle: true, @@ -50,7 +47,9 @@ const cashReplaceMultiGlassPromoInshopData: Partial = { // Override payment details paymentDetails: { - paymentType: PaymentType.PayAtService + paymentType: PaymentType.PayAtService, + // Add promo code + promoCode: '20CALL', }, // Vehicle part questions for multiple glass parts @@ -94,13 +93,13 @@ const cashReplaceMultiGlassPromoInshopData: Partial = { ] } -const cashReplaceMultiGlassPromoInshopTests: TestCase[] = []; +const cashReplaceMultiGlassPromoInshopTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashReplaceMultiGlassPromoInshop`, tags: ['@E2E','@CashReplaceMultiGlassPromoInshop', '@test_report', '@CASH'], testData: cashReplaceMultiGlassPromoInshopData -}, undefined, 'CashReplaceMultiGlassPromoInshop'); +}; cashReplaceMultiGlassPromoInshopTests.push(tc); export default cashReplaceMultiGlassPromoInshopTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashReplaceMultiSlidingGlassDropoff.ts b/playwright-tests/tests/CashReplaceMultiSlidingGlassDropoff.ts index e11f8dce1..088ab9991 100644 --- a/playwright-tests/tests/CashReplaceMultiSlidingGlassDropoff.ts +++ b/playwright-tests/tests/CashReplaceMultiSlidingGlassDropoff.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { VehicleDamage, PartQuestionType, PaymentType, ServicePackage, AppointmentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { VehicleDamage, PartQuestionType, PaymentType, ServicePackage, ServiceLocation } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed before generating any data setFakerSeedFromTestName("CashReplaceMultiSlidingGlassDropoff"); @@ -29,7 +29,7 @@ const cashReplaceMultiSlidingGlassDropoffData: Partial = { // Override for drop-off service appointmentDetails: { - serviceLocation: AppointmentType.DropOff, + serviceLocation: ServiceLocation.DropOff, appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate }, @@ -103,13 +103,13 @@ const cashReplaceMultiSlidingGlassDropoffData: Partial = { ] } -const cashReplaceMultiSlidingGlassDropoffTests: TestCase[] = []; +const cashReplaceMultiSlidingGlassDropoffTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashReplaceMultiSlidingGlassDropoff`, tags: ['@E2E','@CashReplaceMultiSlidingGlassDropoff', '@test_report', '@CASH'], testData: cashReplaceMultiSlidingGlassDropoffData -}, undefined, 'CashReplaceMultiSlidingGlassDropoff'); +}; cashReplaceMultiSlidingGlassDropoffTests.push(tc); export default cashReplaceMultiSlidingGlassDropoffTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashReplaceRainDefensePromoInshop.ts b/playwright-tests/tests/CashReplaceRainDefensePromoInshop.ts index d87da9129..da3dbdc23 100644 --- a/playwright-tests/tests/CashReplaceRainDefensePromoInshop.ts +++ b/playwright-tests/tests/CashReplaceRainDefensePromoInshop.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { ServicePackage, PaymentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { ServicePackage, PaymentType } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed before generating any data setFakerSeedFromTestName("CashReplaceRainDefensePromoInshop"); @@ -15,9 +15,6 @@ const cashReplaceRainDefensePromoInshopData: Partial = { // Key feature: Premium package with Rain Defense servicePackage: ServicePackage.Premium, - // Rain Defense promo code - promoCode: 'rd50', - // Flag for recalibration vehicle isRecalVehicle: true, @@ -45,17 +42,19 @@ const cashReplaceRainDefensePromoInshopData: Partial = { // Payment at service paymentDetails: { - paymentType: PaymentType.PayAtService + paymentType: PaymentType.PayAtService, + // Rain Defense promo code + promoCode: 'rd50' }, } -const cashReplaceRainDefensePromoInshopTests: TestCase[] = []; +const cashReplaceRainDefensePromoInshopTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashReplaceRainDefensePromoInshop`, tags: ['@E2E','@CashReplaceRainDefensePromoInshop', '@test_report', '@CASH'], testData: cashReplaceRainDefensePromoInshopData -}, undefined, 'CashReplaceRainDefensePromoInshop'); +}; cashReplaceRainDefensePromoInshopTests.push(tc); export default cashReplaceRainDefensePromoInshopTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashReplaceSafeliteCanNotRecalMobile.ts b/playwright-tests/tests/CashReplaceSafeliteCanNotRecalMobile.ts index e1a8f577d..355b726a6 100644 --- a/playwright-tests/tests/CashReplaceSafeliteCanNotRecalMobile.ts +++ b/playwright-tests/tests/CashReplaceSafeliteCanNotRecalMobile.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { AppointmentType, PartQuestionType, PaymentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { ServiceLocation, PartQuestionType, PaymentType } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed before generating any data setFakerSeedFromTestName("CashReplaceSafeliteCanNotRecalMobile"); @@ -13,10 +13,10 @@ const cashReplaceSafeliteCanNotRecalMobileData: Partial = { ...getDefaultTestData(), // Get default data with current seed // Special flag to skip estimate page - skipEstimatePage: true, + isSkipEstimatePage: true, // Special flag to verify safelite can not recalibrate in the backend - canNotRecal: true, + isCanNotRecal: true, // Override customer postal code customerDetails: { @@ -42,7 +42,7 @@ const cashReplaceSafeliteCanNotRecalMobileData: Partial = { // Override for mobile service appointmentDetails: { - serviceLocation: AppointmentType.Mobile, + serviceLocation: ServiceLocation.Mobile, appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate, serviceAddress: { // Use street address from current faker seed @@ -69,13 +69,13 @@ const cashReplaceSafeliteCanNotRecalMobileData: Partial = { ] } -const cashReplaceSafeliteCanNotRecalMobileTests: TestCase[] = []; +const cashReplaceSafeliteCanNotRecalMobileTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashReplaceSafeliteCanNotRecalMobile`, tags: ['@E2E','@CashReplaceSafeliteCanNotRecalMobile', '@test_report', '@CASH'], testData: cashReplaceSafeliteCanNotRecalMobileData -}, undefined, 'CashReplaceSafeliteCanNotRecalMobile'); +}; cashReplaceSafeliteCanNotRecalMobileTests.push(tc); export default cashReplaceSafeliteCanNotRecalMobileTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashReplaceVinMobile.ts b/playwright-tests/tests/CashReplaceVinMobile.ts index cf6a9b515..48b17a39f 100644 --- a/playwright-tests/tests/CashReplaceVinMobile.ts +++ b/playwright-tests/tests/CashReplaceVinMobile.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { AppointmentTimeslot, AppointmentType, PaymentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { AppointmentTimeslot, ServiceLocation, PaymentType } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed based on test name for consistent but unique data setFakerSeedFromTestName("CashReplaceVinMobile"); @@ -39,7 +39,7 @@ const cashReplaceVinMobileData: Partial = { // Override for mobile service appointmentDetails: { - serviceLocation: AppointmentType.Mobile, + serviceLocation: ServiceLocation.Mobile, appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate, serviceAddress: { // Use street address from current faker seed @@ -58,13 +58,13 @@ const cashReplaceVinMobileData: Partial = { }, } -const cashReplaceVinMobileTests: TestCase[] = []; +const cashReplaceVinMobileTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashReplaceVinMobile`, tags: ['@E2E','@CashReplaceVinMobile', '@test_report', '@CASH'], testData: cashReplaceVinMobileData -}, undefined, 'CashReplaceVinMobile'); +}; cashReplaceVinMobileTests.push(tc); export default cashReplaceVinMobileTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashReplaceWiperDropoff.ts b/playwright-tests/tests/CashReplaceWiperDropoff.ts index a76858b97..5b79df193 100644 --- a/playwright-tests/tests/CashReplaceWiperDropoff.ts +++ b/playwright-tests/tests/CashReplaceWiperDropoff.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { ServicePackage, AppointmentType, PartQuestionType, PaymentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { ServicePackage, ServiceLocation, PartQuestionType, PaymentType } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed based on test name for consistent but unique data setFakerSeedFromTestName("CashReplaceWiperDropoff"); @@ -16,7 +16,7 @@ const cashReplaceWiperDropoffData: Partial = { servicePackage: ServicePackage.Standard, // Special flags - skipEstimatePage: true, + isSkipEstimatePage: true, isRecalVehicle: true, // Override customer postal code @@ -43,7 +43,7 @@ const cashReplaceWiperDropoffData: Partial = { // Override for drop-off service appointmentDetails: { - serviceLocation: AppointmentType.DropOff, + serviceLocation: ServiceLocation.DropOff, appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate }, @@ -67,13 +67,13 @@ const cashReplaceWiperDropoffData: Partial = { ] } -const cashReplaceWiperDropoffTests: TestCase[] = []; +const cashReplaceWiperDropoffTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashReplaceWiperDropoff`, tags: ['@E2E','@CashReplaceWiperDropoff', '@test_report', '@CASH'], testData: cashReplaceWiperDropoffData -}, undefined, 'CashReplaceWiperDropoff'); +}; cashReplaceWiperDropoffTests.push(tc); export default cashReplaceWiperDropoffTests; \ No newline at end of file diff --git a/playwright-tests/tests/CashReplaceWiperPromoInshop.ts b/playwright-tests/tests/CashReplaceWiperPromoInshop.ts index 66b6acae7..635125299 100644 --- a/playwright-tests/tests/CashReplaceWiperPromoInshop.ts +++ b/playwright-tests/tests/CashReplaceWiperPromoInshop.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { ServicePackage, AppointmentType, PaymentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { ServicePackage, ServiceLocation, PaymentType } from 'safelite-playwright-core'; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed based on test name for consistent but unique data setFakerSeedFromTestName("CashReplaceWiperPromoInShop"); @@ -15,9 +15,6 @@ const cashReplaceWiperPromoInShopData: Partial = { // Key feature: Standard package with wipers servicePackage: ServicePackage.Standard, - // Specific wiper promo code - promoCode: '1WIPER0', - // Override customer postal code customerDetails: { ...getDefaultTestData().customerDetails!, @@ -42,17 +39,19 @@ const cashReplaceWiperPromoInShopData: Partial = { // Payment at service paymentDetails: { - paymentType: PaymentType.PayAtService + paymentType: PaymentType.PayAtService, + // Specific wiper promo code + promoCode: '1WIPER0', } } -const cashReplaceWiperPromoInShopTests: TestCase[] = []; +const cashReplaceWiperPromoInShopTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `CashReplaceWiperPromoInShop`, tags: ['@E2E','@CashReplaceWiperPromoInShop', '@test_report', '@CASH'], testData: cashReplaceWiperPromoInShopData -}, undefined, 'CashReplaceWiperPromoInShop'); +}; cashReplaceWiperPromoInShopTests.push(tc); export default cashReplaceWiperPromoInShopTests; \ No newline at end of file diff --git a/playwright-tests/tests/InsuranceAcuityPaypal.ts b/playwright-tests/tests/InsuranceAcuityPaypal.ts index be8af6e67..b70c60e2d 100644 --- a/playwright-tests/tests/InsuranceAcuityPaypal.ts +++ b/playwright-tests/tests/InsuranceAcuityPaypal.ts @@ -1,9 +1,10 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { PaymentMethod, AppointmentType, DamageType, PartQuestionType, VehicleDamage, PaymentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { ServiceLocation, DamageType, PartQuestionType, VehicleDamage, PaymentType, Flow } from 'safelite-playwright-core'; +import { PaymentMethod } from "framework/localTypes/Enums"; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed based on test name for consistent but unique data setFakerSeedFromTestName("InsuranceAcuityPaypal"); @@ -17,7 +18,7 @@ const insuranceAcuityPaypalData: Partial = { // Insurance claim flags isDuplicateClaim: true, - isPolicyFound: true, + flow: Flow.Managed, isUseVehicleOnPolicy: true, // Override customer details for Kentucky location @@ -56,7 +57,7 @@ const insuranceAcuityPaypalData: Partial = { // Override for in-shop appointment appointmentDetails: { - serviceLocation: AppointmentType.InShop, + serviceLocation: ServiceLocation.InShop, shopAddress: '8985 Yellow Brick Rd, Rosedale, MD 21237', appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate }, @@ -85,13 +86,13 @@ const insuranceAcuityPaypalData: Partial = { paymentDetails: {} } -const insuranceAcuityPaypalTests: TestCase[] = []; +const insuranceAcuityPaypalTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `InsuranceAcuityPaypal`, tags: ['@E2E','@InsuranceAcuityPaypal', '@test_report', '@Insurance'], testData: insuranceAcuityPaypalData -}, undefined, 'InsuranceAcuityPaypal'); +}; insuranceAcuityPaypalTests.push(tc); export default insuranceAcuityPaypalTests; \ No newline at end of file diff --git a/playwright-tests/tests/InsuranceGeico.ts b/playwright-tests/tests/InsuranceGeico.ts index 1490eed7f..f71917ff2 100644 --- a/playwright-tests/tests/InsuranceGeico.ts +++ b/playwright-tests/tests/InsuranceGeico.ts @@ -1,9 +1,10 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { PaymentMethod, AppointmentType, DamageType, PaymentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { ServiceLocation, DamageType, Flow } from 'safelite-playwright-core'; +import { PaymentMethod } from "framework/localTypes/Enums"; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed based on test name for consistent but unique data setFakerSeedFromTestName("InsuranceGeico"); @@ -17,7 +18,7 @@ const insuranceGeicoData: Partial = { // Insurance claim flags isDuplicateClaim: true, - isPolicyFound: true, + flow: Flow.Managed, isUseVehicleOnPolicy: true, // Override customer details with specific name and California location @@ -57,7 +58,7 @@ const insuranceGeicoData: Partial = { // Override for in-shop appointment appointmentDetails: { - serviceLocation: AppointmentType.InShop, + serviceLocation: ServiceLocation.InShop, shopAddress: '8985 Yellow Brick Rd, Rosedale, MD 21237', appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate }, @@ -66,13 +67,13 @@ const insuranceGeicoData: Partial = { paymentDetails: {} } -const insuranceGeicoTests: TestCase[] = []; +const insuranceGeicoTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `InsuranceGeico`, tags: ['@E2E','@InsuranceGeico', '@test_report', '@Insurance'], testData: insuranceGeicoData -}, undefined, 'InsuranceGeico'); +}; insuranceGeicoTests.push(tc); export default insuranceGeicoTests; \ No newline at end of file diff --git a/playwright-tests/tests/InsuranceITAC21stCentury.ts b/playwright-tests/tests/InsuranceITAC21stCentury.ts index 70ce6b528..09646d895 100644 --- a/playwright-tests/tests/InsuranceITAC21stCentury.ts +++ b/playwright-tests/tests/InsuranceITAC21stCentury.ts @@ -1,9 +1,10 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { PaymentMethod, AppointmentType, DamageType, PartQuestionType, PaymentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { ServiceLocation, DamageType, PartQuestionType, Flow } from 'safelite-playwright-core'; +import { PaymentMethod } from "framework/localTypes/Enums"; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed based on test name for consistent but unique data setFakerSeedFromTestName("InsuranceITAC21stCentury"); @@ -17,7 +18,7 @@ const insuranceITAC21stCenturyData: Partial = { // Insurance claim flags isDuplicateClaim: true, - isPolicyFound: true, + flow: Flow.Managed, isUseVehicleOnPolicy: true, isRecalNotification: true, // Special flag for recalibration notification @@ -55,7 +56,7 @@ const insuranceITAC21stCenturyData: Partial = { // Override for in-shop appointment with specific shop appointmentDetails: { - serviceLocation: AppointmentType.InShop, + serviceLocation: ServiceLocation.InShop, appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate, shopAddress: "8160 Masi Dr, Rancho Cucamonga, CA 91730" }, @@ -70,13 +71,13 @@ const insuranceITAC21stCenturyData: Partial = { ] } -const insuranceITAC21stCenturyTests: TestCase[] = []; +const insuranceITAC21stCenturyTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `InsuranceITAC21stCentury`, tags: ['@E2E','@InsuranceITAC21stCentury', '@test_report', '@Insurance'], testData: insuranceITAC21stCenturyData -}, undefined, 'InsuranceITAC21stCentury'); +}; insuranceITAC21stCenturyTests.push(tc); export default insuranceITAC21stCenturyTests; \ No newline at end of file diff --git a/playwright-tests/tests/InsuranceITACOptimizedPriceValidationAllState.ts b/playwright-tests/tests/InsuranceITACOptimizedPriceValidationAllState.ts index 00bac631d..5924830ba 100644 --- a/playwright-tests/tests/InsuranceITACOptimizedPriceValidationAllState.ts +++ b/playwright-tests/tests/InsuranceITACOptimizedPriceValidationAllState.ts @@ -1,9 +1,10 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { VehicleDamage, PaymentMethod, AppointmentType, DamageType, PaymentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleLookupType } from "@business-logic/types/Enums"; -import { getDefaultTestData, setFakerSeedFromTestName } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { VehicleDamage, ServiceLocation, DamageType, Flow } from 'safelite-playwright-core'; +import { PaymentMethod } from "framework/localTypes/Enums"; +import { ITestCase } from '../framework/Typedefs' +import { VehicleLookupType } from 'safelite-playwright-core'; +import { getDefaultTestData, setFakerSeedFromTestName } from 'safelite-playwright-core'; // Set the seed based on test name for consistent but unique data setFakerSeedFromTestName("InsuranceITACOptimizedPriceValidationAllState"); @@ -17,7 +18,7 @@ const insuranceITACOptimizedPriceValidationAllStateData: Partial = { // Insurance claim flags isDuplicateClaim: true, - isPolicyFound: true, + flow: Flow.Managed, isUseVehicleOnPolicy: true, // Override customer details with specific name and location @@ -59,7 +60,7 @@ const insuranceITACOptimizedPriceValidationAllStateData: Partial = { // Override for in-shop appointment with specific shop appointmentDetails: { - serviceLocation: AppointmentType.InShop, + serviceLocation: ServiceLocation.InShop, shopAddress: '8985 Yellow Brick Rd, Rosedale, MD 21237', appointmentDate: getDefaultTestData().appointmentDetails?.appointmentDate }, @@ -67,13 +68,13 @@ const insuranceITACOptimizedPriceValidationAllStateData: Partial = { paymentDetails: {} } -const insuranceITACOptimizedPriceValidationAllStateTests: TestCase[] = []; +const insuranceITACOptimizedPriceValidationAllStateTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `InsuranceITACOptimizedPriceValidationAllState`, tags: ['@E2E','@InsuranceITACOptimizedPriceValidationAllState', '@test_report', '@Insurance'], testData: insuranceITACOptimizedPriceValidationAllStateData -}, undefined, 'InsuranceITACOptimizedPriceValidationAllState'); +}; insuranceITACOptimizedPriceValidationAllStateTests.push(tc); export default insuranceITACOptimizedPriceValidationAllStateTests; \ No newline at end of file diff --git a/playwright-tests/tests/alert-validation/alert0001_HeavyTruck.ts b/playwright-tests/tests/alert-validation/alert0001_HeavyTruck.ts index dad46ecd5..3e6eefc96 100644 --- a/playwright-tests/tests/alert-validation/alert0001_HeavyTruck.ts +++ b/playwright-tests/tests/alert-validation/alert0001_HeavyTruck.ts @@ -1,9 +1,9 @@ //Imports here -import { ITestData } from "@business-logic/types/ITestData" -import { VehicleDamage, AppointmentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { getNextWeekday } from "@impl/utils/DateUtils"; -import { defaultTestData } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData' +import { VehicleDamage, ServiceLocation } from 'safelite-playwright-core'; +import { ITestCase } from '../../framework/Typedefs'; +import { getNextWeekday } from 'safelite-playwright-core'; +import { defaultTestData } from 'safelite-playwright-core'; // Heavy Truck (alert) Test Data const heavyTruckData: Partial = { @@ -25,18 +25,19 @@ const heavyTruckData: Partial = { VehicleDamage.RearWindow ], appointmentDetails: { - serviceLocation: AppointmentType.DropOff, + serviceLocation: ServiceLocation.DropOff, appointmentDate: getNextWeekday() } }; -const heavyTruckTests: TestCase[] = []; +const heavyTruckTests: ITestCase[] = []; -const tc = new TestCase({ +const tc: ITestCase = { name: `alert0001 Heavy Truck`, tags: ['@Alert', '@HeavyTruck', '@test_report'], testData: heavyTruckData -}, undefined, 'HeavyTruck'); +}; + heavyTruckTests.push(tc); export default heavyTruckTests; \ No newline at end of file diff --git a/playwright-tests/tests/alert-validation/alert0002_RepairAndReplace.ts b/playwright-tests/tests/alert-validation/alert0002_RepairAndReplace.ts index aa52ac4e5..060f04b50 100644 --- a/playwright-tests/tests/alert-validation/alert0002_RepairAndReplace.ts +++ b/playwright-tests/tests/alert-validation/alert0002_RepairAndReplace.ts @@ -1,9 +1,9 @@ // Imports here -import { ITestData } from "@business-logic/types/ITestData"; -import { VehicleDamage, AppointmentType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { getNextWeekday } from "@impl/utils/DateUtils"; -import { defaultTestData } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData'; +import { VehicleDamage, ServiceLocation } from 'safelite-playwright-core'; +import { ITestCase } from '../../framework/Typedefs' +import { getNextWeekday } from 'safelite-playwright-core'; +import { defaultTestData } from 'safelite-playwright-core'; // Both repair and replace selected (alert) Test Data const repairAndReplaceData: Partial = { @@ -22,7 +22,7 @@ const repairAndReplaceData: Partial = { VehicleDamage.RearWindow ], appointmentDetails: { - serviceLocation: AppointmentType.DropOff, + serviceLocation: ServiceLocation.DropOff, appointmentDate: getNextWeekday() }, alertFlags: { @@ -30,13 +30,13 @@ const repairAndReplaceData: Partial = { } }; -const repairAndReplaceTests: TestCase[] = []; +const repairAndReplaceTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `alert0002 Both repair and replace selected`, tags: ['@Alert', '@RepairReplace', '@test_report'], testData: repairAndReplaceData -}, undefined, 'RepairReplace'); +}; repairAndReplaceTests.push(tc); export default repairAndReplaceTests; \ No newline at end of file diff --git a/playwright-tests/tests/alert-validation/alert0003_SplitWindshield.ts b/playwright-tests/tests/alert-validation/alert0003_SplitWindshield.ts index f01151b05..b36a8af4c 100644 --- a/playwright-tests/tests/alert-validation/alert0003_SplitWindshield.ts +++ b/playwright-tests/tests/alert-validation/alert0003_SplitWindshield.ts @@ -1,8 +1,8 @@ // Imports here -import { ITestData } from "@business-logic/types/ITestData"; -import TestCase from "@business-logic/types/TestCase"; -import { VehicleDamage } from "@business-logic/types/Enums"; -import { defaultTestData } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData'; +import { ITestCase } from '../../framework/Typedefs' +import { VehicleDamage } from 'safelite-playwright-core'; +import { defaultTestData } from 'safelite-playwright-core'; // Windshield selected, when vehicle has split windshield (alert) Test Data const splitWindshieldData: Partial = { @@ -38,7 +38,7 @@ const vehiclesToTest = [ } ]; -const splitWindshieldTests: TestCase[] = []; +const splitWindshieldTests: ITestCase[] = []; // Generate test cases for each vehicle vehiclesToTest.forEach((vehicle, index) => { @@ -50,11 +50,11 @@ vehiclesToTest.forEach((vehicle, index) => { } }; - const tc = new TestCase({ + const tc = { name: `alert0003_${vehicle.make.toLowerCase()}_${vehicle.model.toLowerCase()} Windshield selected, when vehicle has split windshield - ${vehicle.make} ${vehicle.model} ${vehicle.year}`, tags: ['@Alert', '@SplitWindshield', '@test_report', `@${vehicle.make.toLowerCase()}`], testData: testData - }, undefined, `SpliWindshield${index + 1}`); + }; splitWindshieldTests.push(tc); }); diff --git a/playwright-tests/tests/alert-validation/alert0004_RepairOnly.ts b/playwright-tests/tests/alert-validation/alert0004_RepairOnly.ts index 3dc245ca4..f67e5ba28 100644 --- a/playwright-tests/tests/alert-validation/alert0004_RepairOnly.ts +++ b/playwright-tests/tests/alert-validation/alert0004_RepairOnly.ts @@ -1,9 +1,9 @@ // Imports here -import { ITestData } from "@business-logic/types/ITestData"; -import { VehicleDamage, AppointmentType, VehicleLookupType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { getNextWeekday } from "@impl/utils/DateUtils"; -import { defaultTestData } from "@business-logic/constants/DefaultTestData"; +import { ITestData } from 'framework/TestData'; +import { VehicleDamage, ServiceLocation, VehicleLookupType } from 'safelite-playwright-core'; +import { ITestCase } from '../../framework/Typedefs' +import { getNextWeekday } from 'safelite-playwright-core'; +import { defaultTestData } from 'safelite-playwright-core'; // Replace selected when not offered (alert) Test Data const repairOnlyData: Partial = { @@ -21,7 +21,7 @@ const repairOnlyData: Partial = { VehicleDamage.WindshieldCrack ], appointmentDetails: { - serviceLocation: AppointmentType.DropOff, + serviceLocation: ServiceLocation.DropOff, appointmentDate: getNextWeekday() }, alertFlags: { @@ -29,13 +29,13 @@ const repairOnlyData: Partial = { } }; -const repairOnlyTests: TestCase[] = []; +const repairOnlyTests: ITestCase[] = []; -const tc = new TestCase({ +const tc = { name: `alert0004 Replace selected when not offered`, tags: ['@Alert', '@RepairOnly', '@test_report'], testData: repairOnlyData -}, undefined, 'RepairOnly'); +}; repairOnlyTests.push(tc); export default repairOnlyTests; \ No newline at end of file diff --git a/playwright-tests/tests/alert-validation/alert0005_UnserviceableZip.ts b/playwright-tests/tests/alert-validation/alert0005_UnserviceableZip.ts index 0e70dd79b..a4e3d44b3 100644 --- a/playwright-tests/tests/alert-validation/alert0005_UnserviceableZip.ts +++ b/playwright-tests/tests/alert-validation/alert0005_UnserviceableZip.ts @@ -1,10 +1,10 @@ // Imports here -import { ITestData } from "@business-logic/types/ITestData"; -import { VehicleDamage, AppointmentType, VehicleLookupType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { getNextWeekday } from "@impl/utils/DateUtils"; +import { ITestData } from 'framework/TestData'; +import { VehicleDamage, ServiceLocation, VehicleLookupType } from 'safelite-playwright-core'; +import { ITestCase } from '../../framework/Typedefs' +import { getNextWeekday } from 'safelite-playwright-core'; import { faker } from "@faker-js/faker"; -import { defaultTestData } from "@business-logic/constants/DefaultTestData"; +import { defaultTestData } from 'safelite-playwright-core'; // Unserviceable zip (alert) - Combined test cases for all lookup types const nextWeekday = getNextWeekday(); @@ -29,7 +29,7 @@ const baseUnserviceableZipData: Partial = { VehicleDamage.WindshieldCrack ], appointmentDetails: { - serviceLocation: AppointmentType.DropOff, + serviceLocation: ServiceLocation.DropOff, appointmentDate: nextWeekday }, alertFlags: { @@ -85,7 +85,7 @@ const lookupTypesToTest: LookupTestCase[] = [ } ]; -const unserviceableZipTests: TestCase[] = []; +const unserviceableZipTests: ITestCase[] = []; // Generate test cases for each lookup type lookupTypesToTest.forEach((lookupType, index) => { @@ -106,11 +106,11 @@ lookupTypesToTest.forEach((lookupType, index) => { }; } - const tc = new TestCase({ + const tc = { name: `alert0005 ${lookupType.tag} Lookup Unserviceable zip`, tags: ['@Alert', `@UnserviceableZip_${lookupType.tag}`, '@test_report'], testData: testData - }, undefined, `UnserviceableZip_${lookupType.tag}`); + }; unserviceableZipTests.push(tc); }); diff --git a/playwright-tests/tests/alert-validation/alert0006_InvalidZip.ts b/playwright-tests/tests/alert-validation/alert0006_InvalidZip.ts index 5ffcd3afe..a78cdbd70 100644 --- a/playwright-tests/tests/alert-validation/alert0006_InvalidZip.ts +++ b/playwright-tests/tests/alert-validation/alert0006_InvalidZip.ts @@ -1,10 +1,10 @@ // Imports here -import { ITestData } from "@business-logic/types/ITestData"; -import { VehicleDamage, AppointmentType, VehicleLookupType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { getNextWeekday } from "@impl/utils/DateUtils"; +import { ITestData } from 'framework/TestData'; +import { VehicleDamage, ServiceLocation, VehicleLookupType } from 'safelite-playwright-core'; +import { ITestCase } from '../../framework/Typedefs' +import { getNextWeekday } from 'safelite-playwright-core'; import { faker } from "@faker-js/faker"; -import { defaultTestData } from "@business-logic/constants/DefaultTestData"; +import { defaultTestData } from 'safelite-playwright-core'; // Invalid zip (alert) - Combined test cases for all lookup types const nextWeekday = getNextWeekday(); @@ -29,7 +29,7 @@ const baseInvalidZipData: Partial = { VehicleDamage.WindshieldCrack ], appointmentDetails: { - serviceLocation: AppointmentType.DropOff, + serviceLocation: ServiceLocation.DropOff, appointmentDate: nextWeekday }, alertFlags: { @@ -101,7 +101,7 @@ const lookupTypesToTest: LookupTestCase[] = [ } ]; -const invalidZipTests: TestCase[] = []; +const invalidZipTests: ITestCase[] = []; // Generate test cases for each lookup type lookupTypesToTest.forEach((lookupType) => { @@ -122,11 +122,11 @@ lookupTypesToTest.forEach((lookupType) => { }; } - const tc = new TestCase({ + const tc = { name: `alert0006 ${lookupType.displayName} Lookup Invalid zip`, tags: ['@Alert', `@InvalidZip_${lookupType.tag}`, '@test_report'], testData: testData - }, undefined, `InvalidZip_${lookupType.tag}`); + }; invalidZipTests.push(tc); }); diff --git a/playwright-tests/tests/alert-validation/alert0007_VinNotFound.ts b/playwright-tests/tests/alert-validation/alert0007_VinNotFound.ts index fccf12662..404fe4b33 100644 --- a/playwright-tests/tests/alert-validation/alert0007_VinNotFound.ts +++ b/playwright-tests/tests/alert-validation/alert0007_VinNotFound.ts @@ -1,10 +1,10 @@ // Imports here -import { ITestData } from "@business-logic/types/ITestData"; -import { VehicleDamage, AppointmentType, VehicleLookupType } from "@business-logic/types/Enums"; -import TestCase from "@business-logic/types/TestCase"; -import { getNextWeekday } from "@impl/utils/DateUtils"; +import { ITestData } from 'framework/TestData'; +import { VehicleDamage, ServiceLocation, VehicleLookupType } from 'safelite-playwright-core'; +import { ITestCase } from '../../framework/Typedefs' +import { getNextWeekday } from 'safelite-playwright-core'; import { faker } from "@faker-js/faker"; -import { defaultTestData } from "@business-logic/constants/DefaultTestData"; +import { defaultTestData } from 'safelite-playwright-core'; // Vin not found (alert) - Combined test cases for all lookup types const nextWeekday = getNextWeekday(); @@ -29,7 +29,7 @@ const baseVinNotFoundData: Partial = { VehicleDamage.WindshieldCrack ], appointmentDetails: { - serviceLocation: AppointmentType.DropOff, + serviceLocation: ServiceLocation.DropOff, appointmentDate: nextWeekday }, alertFlags: { @@ -111,7 +111,7 @@ const lookupTypesToTest: LookupTestCase[] = [ } ]; -const vinNotFoundTests: TestCase[] = []; +const vinNotFoundTests: ITestCase[] = []; // Generate test cases for each lookup type lookupTypesToTest.forEach((lookupType) => { @@ -132,11 +132,11 @@ lookupTypesToTest.forEach((lookupType) => { }; } - const tc = new TestCase({ + const tc = { name: `alert0007 ${lookupType.displayName} Lookup Vin Not Found`, tags: ['@Alert', `@VinNotFound_${lookupType.tag}`, '@test_report'], testData: testData - }, undefined, `VinNotFound_${lookupType.tag}`); + }; vinNotFoundTests.push(tc); }); diff --git a/playwright-tests/tsconfig.json b/playwright-tests/tsconfig.json index b9d0a59db..717c7217e 100644 --- a/playwright-tests/tsconfig.json +++ b/playwright-tests/tsconfig.json @@ -11,10 +11,6 @@ "emitDecoratorMetadata": true, "experimentalDecorators": true, "baseUrl": ".", - "rootDirs": [ - "./impl", - "./business-logic" - ], "paths": { "@impl/*": [ "./impl/*" @@ -40,15 +36,6 @@ "@mixins/*": [ "./impl/gui/mixins" ], - "@business-logic/*": [ - "./business-logic/*" - ], - "@validations/*": [ - "./business-logic/validations/*" - ], - "@workflows/*": [ - "./business-logic/workflows/*" - ], "@helpers/*": [ "./helpers/*" ],