diff --git a/e2e.md b/e2e.md new file mode 100644 index 0000000..2813260 --- /dev/null +++ b/e2e.md @@ -0,0 +1,152 @@ +# End-to-End (E2E) Tests +E2E tests, located in `e2e/`, aim to verify the complete functionality of the application. They cover scenarios such as user authentication, navigation, and interactions with different pages. + +## E2E scenarios + +### login.spec.ts + +1. **Should Login with user "standard_user"** + - Description: Verify that `standard_user` can successfully log in. + - Steps: Navigate to the login page, enter valid credentials for standard_user, and confirm successful login. + +2. **Should Login with user "visual_user"** + - Description: Verify that `visual_user` can successfully log in. + - Steps: Navigate to the login page, enter valid credentials for a visual user, and ensure successful login. + +3. **Should Login with user "error_user"** + - Description: Verify that `error_user` can successfully log in. + - Steps: Attempt to log in with the credentials of a user prone to errors and validate the system's response. + +4. **Should Login with user "problem_user"** + - Description: Verify that `problem_user` can successfully log in. + - Steps: Log in using the credentials of a user known for causing problems and analyze the system's response. + +5. **Should Login with user "performance_user"** + - Description: Validate the `performance_user`'s behavior when a known problematic user attempts to log in. + - Steps: Log in using the credentials of a user specifically used for performance testing and assess the login speed. + +6. **Should Not Login with Wrong Credentials** + - Description: Confirm that the system rejects login attempts with incorrect credentials. + - Steps: Attempt to log in with invalid username and password combinations and verify that the system denies access. + +7. **Should Not Login with Locked User** + - Description: Test the system's response when attempting to log in with a locked user account. + - Steps: Use the credentials of a locked user account and check for the expected system behavior. + +8. **Should Not Login with Empty User** + - Description: Confirm that login is not possible with an empty username field. + - Steps: Attempt to log in without entering a username and validate the system's response. + +9. **Should Not Login with Empty Password** + - Description: Verify that login is not allowed when the password field is left empty. + - Steps: Attempt to log in without entering a password and confirm the expected system behavior. + +10. **Should Not Login with Empty Credential** + - Description: Test the system's response to an attempt to log in without entering any credentials. + - Steps: Try to log in without providing any username or password and ensure that access is denied. + +### inventory.spec.ts + +1. **Should List by Name (Z to A)** + - Description: Confirm that the inventory items are displayed in descending order by name. + - Steps: Navigate to the inventory page, select the "Z to A" sorting option, and validate the item order. + +2. **Should List by Name (A to Z)** + - Description: Ensure that the inventory items are displayed in ascending order by name. + - Steps: Navigate to the inventory page, select the "A to Z" sorting option, and verify the item order. + +3. **Should List by Price (Low to High)** + - Description: Validate that the inventory items are sorted from low to high based on price. + - Steps: Navigate to the inventory page, select the "Low to High" sorting option, and check the item order. + +4. **Should List by Price (High to Low)** + - Description: Check that the inventory items are sorted from high to low based on price. + - Steps: Navigate to the inventory page, select the "High to Low" sorting option, and confirm the item order. + +5. **Should Add to Cart and Then Remove from Cart** + - Description: Test the ability to add an item to the cart and subsequently remove it. + - Steps: Add an item to the cart, remove the added item. + +### inventoryItem.spec.ts + +1. **Should Add to Cart and Update Cart Counter** + - Description: Confirm that adding an item to the cart updates the cart counter. + - Steps: Navigate to an item's detailed view, add item to the cart and verify that the cart counter reflects the updated count. + +2. **Should Remove from Cart and Update Cart Counter** + - Description: Verify that removing an item from the cart updates the cart counter accordingly. + - Steps: Navigate to an item's detailed view, add item to the cart, remove it, and check that the cart counter is decremented. + +3. **Should Return to Inventory Page** + - Description: Test the functionality to return to the inventory page from an item-specific view. + - Steps: Navigate to an item's detailed view, use the back button, and confirm returning to the inventory page. + +### cart.spec.ts + +1. **Should Remove Item and Decrease Cart Counter** + - **Description:** Validate that removing an item from the cart results in a decrease in the cart counter. + - **Steps:** Add an item to the cart, note the initial cart count, remove the item, and confirm the cart counter is decremented. + +2. **Should Remove All Items** + - **Description:** Test the ability to remove all items from the cart. + - **Steps:** Add multiple items to the cart, initiate the removal of all items, and verify that the cart is empty afterward. + +3. **Should Continue Shopping** + - **Description:** Confirm the functionality to continue shopping from the cart. + - **Steps:** Navigate to the cart, choose to continue shopping, and ensure a return to the inventory page. + +4. **Should Checkout** + - **Description:** Validate the checkout process initiated from the cart. + - **Steps:** Add an item to the cart, proceed to checkout, and confirm successful navigation to the checkout process. + +### checkout.spec.ts + +1. **Should Checkout and Go Back Home** + - Description: Confirm the successful checkout process, leading back to the home page. + - Steps: Go through the checkout process, complete the purchase, and validate redirection to the home page. + +2. **Should Not Checkout with Empty Form** + - Description: Validate that attempting to check out with an empty form is not allowed. + - Steps: Initiate the checkout process with an empty form and confirm the expected system behavior. + +3. **Should Not Checkout Without First Name** + - Description: Confirm that checkout is not possible without entering a first name. + - Steps: Start the checkout process without providing a first name and validate the system's response. + +4. **Should Not Checkout Without Last Name** + - Description: Verify that checkout requires entering a last name. + - Steps: Attempt to check out without providing a last name and ensure the expected system behavior. + +5. **Should Not Checkout Without Zip Code** + - Description: Confirm that a zip code is a required field for the checkout process. + - Steps: Start the checkout without entering a zip code and check for the system's expected response. + +6. **Should Cancel Checkout on Step One** + - Description: Test the ability to cancel the checkout process on the first step. + - Steps: Begin the checkout process and choose to cancel at the first step, verifying a return to the previous state. + +7. **Should Cancel Checkout on Step Two** + - Description: Confirm that the checkout process can be canceled on the second step. + - Steps: Progress to the second step of checkout and choose to cancel, checking for the expected system behavior. + +### menu.spec.ts + +1. **Should Open and Close Menu** + - **Description:** Verify that the menu can be successfully opened and closed. + - **Steps:** Open the menu, confirm its visibility, close the menu, and validate its closure. + +2. **Should Reset App State** + - **Description:** Test the functionality to reset the application state from the menu. + - **Steps:** Navigate to the menu, choose the option to reset the app state, and confirm a reset. + +3. **Should Visit About** + - **Description:** Confirm that the "About" section is accessible from the menu. + - **Steps:** Open the menu, select the "About" option, and validate successful navigation to the "About" page. + +4. **Should Visit All Items** + - **Description:** Validate the ability to visit the "Inventory" page from the menu. + - **Steps:** Open the menu, choose the "All Items" option, and confirm successful navigation to the corresponding page. + +5. **Should Logout** + - **Description:** Test the logout functionality from the menu. + - **Steps:** Open the menu, select the logout option, and confirm the expected logout behavior. \ No newline at end of file diff --git a/playwright.config.ts b/playwright.config.ts index fb29bf7..6956b8b 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -100,50 +100,74 @@ export default defineConfig({ // dependencies: ['setup'], // }, { - name: 'visual', + name: 'visual on Desktop Chrome', testMatch: '**/visual/*.spec.ts', use: { ...devices['Desktop Chrome'], } }, - - // { - // name: 'firefox', - // use: { - // ...devices['Desktop Firefox'], - // storageState: STORAGE_STATE_DEFAULT_USER - // }, - // dependencies: ['setup'], - // }, - - // { - // name: 'webkit', - // use: { - // ...devices['Desktop Safari'], - // storageState: STORAGE_STATE_DEFAULT_USER - // }, - // dependencies: ['setup'], - // }, - - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { ...devices['Pixel 5'] }, - // }, - // { - // name: 'Mobile Safari', - // use: { ...devices['iPhone 12'] }, - // }, - - /* Test against branded browsers. */ - // { - // name: 'Microsoft Edge', - // use: { ...devices['Desktop Edge'], channel: 'msedge' }, - // }, - // { - // name: 'Google Chrome', - // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, - // }, + { + name: 'visual on Pixel 5', + testMatch: '**/visual/*.spec.ts', + use: { + ...devices['Pixel 5'], + } + }, + { + name: 'visual on iPhone 12', + testMatch: '**/visual/*.spec.ts', + use: { + ...devices['iPhone 12'], + } + }, + /* UI Test */ + { + name: 'UI on Desktop Chrome', + testMatch: '**/ui/*.spec.ts', + use: { + ...devices['Desktop Chrome'], + storageState: STORAGE_STATE_DEFAULT_USER + }, + dependencies: ['setup'], + }, + { + name: 'UI on Desktop Firefox', + testMatch: '**/ui/*.spec.ts', + use: { + ...devices['Desktop Firefox'], + storageState: STORAGE_STATE_DEFAULT_USER + }, + dependencies: ['setup'], + }, + { + name: 'UI on Desktop Safari', + testMatch: '**/ui/*.spec.ts', + use: { + ...devices['Desktop Safari'], + storageState: STORAGE_STATE_DEFAULT_USER + }, + dependencies: ['setup'], + }, + { + name: 'UI on Pixel 5', + testMatch: '**/ui/*.spec.ts', + grepInvert: /@responsive/, + use: { + ...devices['Pixel 5'], + storageState: STORAGE_STATE_DEFAULT_USER + }, + dependencies: ['setup'], + }, + { + name: 'UI on Iphone 12', + testMatch: '**/ui/*.spec.ts', + grepInvert: /@responsive/, + use: { + ...devices['iPhone 12'], + storageState: STORAGE_STATE_DEFAULT_USER + }, + dependencies: ['setup'], + } ], /* Run your local dev server before starting the tests */ diff --git a/readme.md b/readme.md index 071f5cb..24538c2 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,12 @@ # Playwright E2E Testing Project for saucedemo.com Hello! This is my E2E testing project for [soucedemo.com](soucedemo.com) using Playwright and TypeScript! I developed this project as part of my learning journey in test automation. -Check the [test report](ecureuill.github.io/saucedemo-playwright) + +The workflow, defined in the `.github/workflows/playwright.yml` file, executes Playwright tests on specified browsers and operating systems. After the test execution, Playwright generates a comprehensive report detailing both passed and failed scenarios. The GitHub Actions workflow is set up to automatically publish this Playwright test report to GitHub Pages. + +This integration ensures that the latest Playwright test results are readily available, providing transparency and visibility into the testing process. + +The generated report, showcasing insights into the results of the Playwright tests, is accessible at [ecureuill.github.io/saucedemo-playwright](ecureuill.github.io/saucedemo-playwright). ## Technologies Used @@ -32,6 +37,9 @@ saucedemo/ │ ├── e2e/ │ │ └── login.spec.ts │ │ └── ... +│ ├── ui/ +│ │ └── login.spec.ts +│ │ └── ... │ ├── visual/ │ │ └── visual.spec.ts │ └── auth.setup.ts @@ -45,11 +53,20 @@ saucedemo/ ### 1. End-to-End (E2E) Tests -E2E tests, located in `e2e/`, aim to verify the complete functionality of the application. They cover scenarios such as user authentication, navigation, and interactions with different pages. +E2E tests, located in `e2e/`, aim to verify the complete functionality of the application. They cover scenarios such as user authentication, navigation, and interactions with different pages. + +Check all scenarios [here](/e2e.md). ### 2. Visual Snapshot Tests -Visual snapshot tests, in `visual/`, focus on ensuring visual consistency across different test runs. They use Playwright's screenshot capabilities to compare and verify changes in the interface. +Visual snapshot tests, located in the `visual/` directory, play a crucial role in ensuring the visual consistency of the application across various test runs. Leveraging Playwright's powerful screenshot capabilities, these tests capture valid screenshots while navigating through the site in the context of a `standard_user`. Subsequently, the application's interface is tested against these baseline screenshots, this time with the user logged in as `visual_user`. This comparison process helps identify and verify any changes in the interface, ensuring a consistent and visually appealing user experience. + +### 2. User Interface (UI) Tests + +The UI tests, located in the `ui/` directory, are designed to scrutinize essential aspects such as usability, layout integrity, responsiveness, and the visual aesthetics of the application. In this initial version, responsiveness is assessed by simulating window resizing, and the integrity of the layout is validated. In upcoming versions, the testing scope will be expanded to delve deeper into these initiated aspects, while also addressing additional facets for a more comprehensive evaluation of the application's user interface. + +Check all scenarios [here](/ui.md). + ## Page Objects and Componentization diff --git a/tests/components/CheckoutFormComponent.ts b/tests/components/CheckoutFormComponent.ts index 9972db9..9327ce1 100644 --- a/tests/components/CheckoutFormComponent.ts +++ b/tests/components/CheckoutFormComponent.ts @@ -23,7 +23,7 @@ export class CheckoutFormComponent extends FormComponent { await this.locatorZipCodeInput.fill(data.zipCode); } - override validateErrorUX = async (): Promise => { + override validateErrorLayout = async (): Promise => { await expect(this.locatorSubmitButton).toHaveText('Continue'); await expect(this.locatorFirstNameInput).toBeVisible(); @@ -41,10 +41,10 @@ export class CheckoutFormComponent extends FormComponent { await expect(this.locatorZipCodeInput).toHaveAttribute('placeholder', 'Zip/Postal Code'); await expect(this.locatorZipCodeInput).toHaveClass(/\berror\b/); - return super.validateErrorUX(); + return super.validateErrorLayout(); } - override validateDefaultUx = async (): Promise => { + override validateDefaultLayout = async (): Promise => { await expect(this.locatorSubmitButton).toHaveText('Continue'); await expect(this.locatorFirstNameInput).toBeVisible(); @@ -62,7 +62,7 @@ export class CheckoutFormComponent extends FormComponent { await expect(this.locatorZipCodeInput).toHaveAttribute('placeholder', 'Zip/Postal Code'); await expect(this.locatorZipCodeInput).not.toHaveClass(/\berror\b/); - return super.validateDefaultUx(); + return super.validateDefaultLayout(); } } \ No newline at end of file diff --git a/tests/components/FooterComponent.ts b/tests/components/FooterComponent.ts index 6b6e7b7..ff26893 100644 --- a/tests/components/FooterComponent.ts +++ b/tests/components/FooterComponent.ts @@ -19,7 +19,7 @@ export class FooterComponent { this.locatorLinkedinLink = this.locatorFooter.getByRole('link', { name: 'Linkedin' }); } - validateDefaultUX = async () => { + validateDefaultLayout = async () => { await expect(this.locatorCopyRights).toBeVisible(); await expect(this.locatorTwitterLink).toBeVisible(); await expect(this.locatorFacebookLink).toBeVisible(); diff --git a/tests/components/FormComponent.ts b/tests/components/FormComponent.ts index 0ea8573..9b6b2d8 100644 --- a/tests/components/FormComponent.ts +++ b/tests/components/FormComponent.ts @@ -29,7 +29,7 @@ export abstract class FormComponent { * * ``` */ - async validateErrorUX(){ + async validateErrorLayout(){ await expect(this.locatorForm).toBeVisible(); await expect(this.locatorForm.locator('input:not([type=submit]).error')).not.toHaveCount(0); await expect(this.locatorForm.locator('svg.error_icon')).not.toHaveCount(0); @@ -41,7 +41,7 @@ export abstract class FormComponent { /** * When form is valid, no input field should have error styles not error icon */ - async validateDefaultUx() { + async validateDefaultLayout() { await expect(this.locatorForm).toBeVisible(); await expect(this.locatorForm.locator('input:not([type=submit]).error')).toHaveCount(0); await expect(this.locatorForm.locator('svg.error_icon')).toHaveCount(0); @@ -49,4 +49,12 @@ export abstract class FormComponent { await expect(this.locatorSubmitButton).toBeVisible(); } + validateFormFieldsAreNotOverlapped = async () => { + const locatorFormFields = await this.locatorForm.locator('input').all(); + + for(const field of locatorFormFields){ + await expect(field.evaluate(node => (node as HTMLElement).offsetParent !== null)).toBe(true); + } + } + } \ No newline at end of file diff --git a/tests/components/HeaderComponent.ts b/tests/components/HeaderComponent.ts index 8af33b8..86cb969 100644 --- a/tests/components/HeaderComponent.ts +++ b/tests/components/HeaderComponent.ts @@ -19,7 +19,7 @@ export class HeaderComponent { this.locatorMenuButton = this.page.getByRole('button', { name: 'Open Menu' }); } - validateDefaultUX = async () => { + validateDefaultLayout = async () => { await expect(this.locatorHeading).toBeVisible(); await expect(this.locatorCartLink).toBeVisible(); await expect(this.locatorMenuButton).toBeVisible(); diff --git a/tests/components/LoginFormComponent.ts b/tests/components/LoginFormComponent.ts index 4ae9245..8af0a34 100644 --- a/tests/components/LoginFormComponent.ts +++ b/tests/components/LoginFormComponent.ts @@ -19,7 +19,7 @@ export class LoginFormComponent extends FormComponent { await this.locatorPasswordInput.fill(data.password); } - override validateErrorUX = async (): Promise => { + override validateErrorLayout = async (): Promise => { await expect(this.locatorSubmitButton).toHaveText('Login'); await expect(this.locatorUsernameInput).toBeVisible(); @@ -32,10 +32,10 @@ export class LoginFormComponent extends FormComponent { await expect(this.locatorPasswordInput).toHaveAttribute('placeholder', 'Password', {ignoreCase: false}); await expect(this.locatorPasswordInput).toHaveClass(/\berror\b/); - super.validateErrorUX(); + super.validateErrorLayout(); } - override validateDefaultUx = async (): Promise => { + override validateDefaultLayout = async (): Promise => { await expect(this.locatorSubmitButton).toHaveText('Login'); await expect(this.locatorUsernameInput).toBeVisible(); @@ -49,7 +49,7 @@ export class LoginFormComponent extends FormComponent { await expect(this.locatorPasswordInput).toHaveAttribute('placeholder', 'Password', {ignoreCase: false}); await expect(this.locatorPasswordInput).not.toHaveClass(/\berror\b/); - return super.validateDefaultUx(); + return super.validateDefaultLayout(); } } \ No newline at end of file diff --git a/tests/components/MenuComponent.ts b/tests/components/MenuComponent.ts index e9e982e..25f52d3 100644 --- a/tests/components/MenuComponent.ts +++ b/tests/components/MenuComponent.ts @@ -19,7 +19,7 @@ export class MenuComponent { this.locatorResetLink = this.locatorMenuNav.getByRole('link', { name: 'Reset App State' }); this.locatorLogoutLink = this.locatorMenuNav.getByRole('link', { name: 'Logout' }); } - validateDefaultUX = async () => { + validateDefaultLayout = async () => { await expect(this.locatorMenuNav).toBeVisible(); await expect(this.locatorCloseMenuButton).toBeVisible(); await expect(this.locatorAllItemsLink).toBeVisible(); diff --git a/tests/components/ProductItemComponent.ts b/tests/components/ProductItemComponent.ts index 67662fa..8b8fcf1 100644 --- a/tests/components/ProductItemComponent.ts +++ b/tests/components/ProductItemComponent.ts @@ -36,7 +36,7 @@ export class ProductItemComponent { await expect(this.locatorRemoveCartButton).toBeVisible(); } - validateAddUX =async () => { + validateAddLayout =async () => { await expect(this.locatorRemoveCartButton).not.toBeVisible(); await expect(this.locatorAddCartButton).toBeVisible(); } diff --git a/tests/e2e/cart.spec.ts b/tests/e2e/cart.spec.ts index 1c3a71a..8998fa2 100644 --- a/tests/e2e/cart.spec.ts +++ b/tests/e2e/cart.spec.ts @@ -21,13 +21,6 @@ test.beforeEach(async ({page}) => { }) -test.describe('Cart UX', () => { - - test('Should have default UX', async () => { - await cartPage.validateDefaultUX(); - }) -}); - test.describe('Cart features', () => { test('Should remove item and decrease cart counter', async () => { diff --git a/tests/e2e/checkoutOne.spec.ts b/tests/e2e/checkoutOne.spec.ts index a0f47a2..e40a334 100644 --- a/tests/e2e/checkoutOne.spec.ts +++ b/tests/e2e/checkoutOne.spec.ts @@ -29,34 +29,6 @@ test.beforeEach(async ({page})=> { await cartPage.checkout(); }) -test.describe('Checkout Step One UX', () => { - test('Should have default UX', async () => { - await checkoutOnePage.validateDefaultUX(); - }) - - test('Should have Error UX on invalid form', async () => { - await checkoutOnePage.form.submit(); - await checkoutOnePage.validateErrorUX(); - }) -}); - -test.describe('Checkout Step Two UX', () => { - test('Should have default UX', async () => { - await checkoutOnePage.form.fill(dataCheckout.success); - await checkoutOnePage.form.submit(); - await checkoutTwoPage.validateDefaultUX(); - }) -}); - -test.describe('Checkout Complete UX', () => { - test('Should have default UX', async () => { - await checkoutOnePage.form.fill(dataCheckout.success); - await checkoutOnePage.form.submit(); - await checkoutTwoPage.finish(); - await checkoutCompletePage.validateDefaultUX(); - }) -}); - test.describe('Checkout features', () => { test('Should checkout and go back home', async ({page}) => { await checkoutOnePage.form.fill(dataCheckout.success); @@ -84,28 +56,28 @@ test.describe('Checkout features', () => { test('Should not checkout with empty form', async () => { await checkoutOnePage.form.fill(dataCheckout.empty); await checkoutOnePage.form.submit(); - await checkoutOnePage.validateErrorUX(); + await checkoutOnePage.validateErrorLayout(); await checkoutOnePage.form.errorComponent.hasMessage('First Name is required'); }); test('Should not checkout without first name', async () => { await checkoutOnePage.form.fill(dataCheckout.empty_firstName); await checkoutOnePage.form.submit(); - await checkoutOnePage.validateErrorUX(); + await checkoutOnePage.validateErrorLayout(); await checkoutOnePage.form.errorComponent.hasMessage('First Name is required'); }); test('Should not checkout without last name', async () => { await checkoutOnePage.form.fill(dataCheckout.empty_lastName); await checkoutOnePage.form.submit(); - await checkoutOnePage.validateErrorUX(); + await checkoutOnePage.validateErrorLayout(); await checkoutOnePage.form.errorComponent.hasMessage('Last Name is required'); }); test('Should not checkout without zip code', async () => { await checkoutOnePage.form.fill(dataCheckout.empty_zipCode); await checkoutOnePage.form.submit(); - await checkoutOnePage.validateErrorUX(); + await checkoutOnePage.validateErrorLayout(); await checkoutOnePage.form.errorComponent.hasMessage('Postal Code is required'); }); diff --git a/tests/e2e/inventory.spec.ts b/tests/e2e/inventory.spec.ts index 2d9254b..934b4b1 100644 --- a/tests/e2e/inventory.spec.ts +++ b/tests/e2e/inventory.spec.ts @@ -11,21 +11,6 @@ test.beforeEach( async ({page}) => { await inventoryPage.visit(); }); -test.describe('Inventory UX', () => { - - test('Should have default UX', async ({page}) => { - await inventoryPage.validateDefaultUX(); - }) - - test('Should alternate Add To Cart button and Remove button when add/remove item to/from cart', async () => { - const index = Math.floor(Math.random()*inventoryPage.items.length); - await inventoryPage.items[index].addToCart(); - await inventoryPage.items[index].validateRemoveUX(); - await inventoryPage.items[index].removeFromCart(); - await inventoryPage.items[index].validateAddUX(); - }) -}) - test.describe('Inventory features', () => { test('Should list by Name (Z to A)', async () => { await inventoryPage.sort(SortOptions.ZA); @@ -72,48 +57,3 @@ test.describe('Inventory features', () => { await new InventoryItemPage(page, data.az[0]).toBe(); }); }); - -test.describe('Menu, Header, Footer', () => { - test('Should have default UX', async () => { - await inventoryPage.header.validateDefaultUX(); - await inventoryPage.footer.validateDefaultUX(); - await inventoryPage.header.openMenu(); - await inventoryPage.header.menu.validateDefaultUX(); - }); - - test.describe('Menu features', () => { - test('Should open and close menu', async () => { - await inventoryPage.header.menu.isClosed(); - await inventoryPage.header.openMenu(); - await inventoryPage.header.menu.isOpened(); - await inventoryPage.header.menu.close(); - await inventoryPage.header.menu.isClosed(); - }); - - test('Should reset app state', async () => { - await inventoryPage.items[0].addToCart(); - await inventoryPage.header.cartCounter(1); - await inventoryPage.header.openMenu(); - await inventoryPage.header.menu.reset(); - await inventoryPage.header.cartCounter(0); - }) - - test('Should visit about', async () => { - await inventoryPage.header.openMenu(); - await inventoryPage.header.menu.visitAbout(); - }) - - test('Should visit All Items', async () => { - await inventoryPage.header.visitCart(); - await inventoryPage.header.openMenu(); - await inventoryPage.header.menu.visitItems(); - await inventoryPage.toBe(); - }) - - test('Should logout', async ({page}) => { - await inventoryPage.header.openMenu(); - await inventoryPage.header.menu.visitLogout(); - await expect(page).toHaveURL('/'); - }) - }) -}) \ No newline at end of file diff --git a/tests/e2e/inventoryItem.spec.ts b/tests/e2e/inventoryItem.spec.ts index d2d5151..61c3369 100644 --- a/tests/e2e/inventoryItem.spec.ts +++ b/tests/e2e/inventoryItem.spec.ts @@ -17,20 +17,6 @@ test.beforeEach(async ({page}) => { await inventoryPage.items[PROD_INDEX_IN_CART].addToCart(); }); -test.describe('Inventory Item UX', () => { - test('Should have default UX when accessing a product that is not added', async () => { - await inventoryPage.items[PROD_INDEX_OUT_CART].openDetailsClickingOnPhoto(); - await inventoryItemPage.validateDefaultUX(); - - - }); - - test('Should have remove UX when accessing a product that is added', async () => { - await inventoryPage.items[PROD_INDEX_IN_CART].openDetailsClickingOnPhoto(); - await inventoryItemInPage.validateRemoveUX(); - }); -}); - test.describe('Inventory Item features', async () => { test('Should add to cart and update cart counter', async () => { await inventoryPage.items[PROD_INDEX_OUT_CART].openDetailsClickingOnPhoto(); diff --git a/tests/e2e/login.spec.ts b/tests/e2e/login.spec.ts index ff1cac5..30d9ea6 100644 --- a/tests/e2e/login.spec.ts +++ b/tests/e2e/login.spec.ts @@ -1,92 +1,80 @@ -import { test } from '@playwright/test'; -import { LoginPage } from '../pages/LoginPage'; -import data from '../fixtures/data/users.json'; -import { InventoryPage } from '../pages/InventoryPage'; -let loginPage: LoginPage; +// import { test } from '@playwright/test'; +// import { LoginPage } from '../pages/LoginPage'; +// import data from '../fixtures/data/users.json'; +// import { InventoryPage } from '../pages/InventoryPage'; +// let loginPage: LoginPage; -test.use({ storageState: { cookies: [], origins: [] } }); +// test.use({ storageState: { cookies: [], origins: [] } }); -test.beforeEach(async ({page}) => { - loginPage = new LoginPage(page); - await loginPage.visit(); - await loginPage.toBe(); -}) +// test.beforeEach(async ({page}) => { +// loginPage = new LoginPage(page); +// await loginPage.visit(); +// await loginPage.toBe(); +// }) -test.describe('login UX', () => { - test('should have default UX on start', async ({page}) => { - await loginPage.validateDefaultUX(); - }) +// test.describe('login feature', () => { +// test('should login', async ({ page }) => { +// await loginPage.formComponent.fill(data.success); +// await loginPage.formComponent.submit() +// await new InventoryPage(page).toBe(); +// }); - test('should have Error UX on invalid form', async ({page}) => { - await loginPage.formComponent.submit() - await loginPage.validateErrorUX(); - }) +// test('should login with visual user', async ({ page }) => { +// await loginPage.formComponent.fill(data.visual_user); +// await loginPage.formComponent.submit() +// await new InventoryPage(page).toBe(); +// }); -}); +// test('should login with error user', async ({ page }) => { +// await loginPage.formComponent.fill(data.error_user); +// await loginPage.formComponent.submit() +// await new InventoryPage(page).toBe(); +// }); -test.describe('login feature', () => { - test('should login', async ({ page }) => { - await loginPage.formComponent.fill(data.success); - await loginPage.formComponent.submit() - await new InventoryPage(page).toBe(); - }); +// test('should login with problem user', async ({ page }) => { +// await loginPage.formComponent.fill(data.problem_user); +// await loginPage.formComponent.submit() +// await new InventoryPage(page).toBe(); +// }); - test('should login with visual user', async ({ page }) => { - await loginPage.formComponent.fill(data.visual_user); - await loginPage.formComponent.submit() - await new InventoryPage(page).toBe(); - }); - - test('should login with error user', async ({ page }) => { - await loginPage.formComponent.fill(data.error_user); - await loginPage.formComponent.submit() - await new InventoryPage(page).toBe(); - }); - - test('should login with problem user', async ({ page }) => { - await loginPage.formComponent.fill(data.problem_user); - await loginPage.formComponent.submit() - await new InventoryPage(page).toBe(); - }); - - test('should login with performance user', async ({ page }) => { - await loginPage.formComponent.fill(data.performance_user); - await loginPage.formComponent.submit() - await new InventoryPage(page).toBe(); - }); +// test('should login with performance user', async ({ page }) => { +// await loginPage.formComponent.fill(data.performance_user); +// await loginPage.formComponent.submit() +// await new InventoryPage(page).toBe(); +// }); - test('should not login with wrong credentials', async({page}) => { - await loginPage.formComponent.fill(data.bad_credential); - await loginPage.formComponent.submit() - await loginPage.validateErrorUX(); - await loginPage.formComponent.errorComponent.hasMessage('Username and password do not match any user in this service'); - }) +// test('should not login with wrong credentials', async({page}) => { +// await loginPage.formComponent.fill(data.bad_credential); +// await loginPage.formComponent.submit() +// await loginPage.validateErrorUX(); +// await loginPage.formComponent.errorComponent.hasMessage('Username and password do not match any user in this service'); +// }) - test('should not login with locked user', async({page}) => { - await loginPage.formComponent.fill(data.locked_user); - await loginPage.formComponent.submit() - await loginPage.validateErrorUX(); - await loginPage.formComponent.errorComponent.hasMessage('Sorry, this user has been locked out.'); - }) +// test('should not login with locked user', async({page}) => { +// await loginPage.formComponent.fill(data.locked_user); +// await loginPage.formComponent.submit() +// await loginPage.validateErrorUX(); +// await loginPage.formComponent.errorComponent.hasMessage('Sorry, this user has been locked out.'); +// }) - test('should not login with empty user', async({page}) => { - await loginPage.formComponent.fill(data.empty_user); - await loginPage.formComponent.submit() - await loginPage.validateErrorUX(); - await loginPage.formComponent.errorComponent.hasMessage('Username is required'); - }) +// test('should not login with empty user', async({page}) => { +// await loginPage.formComponent.fill(data.empty_user); +// await loginPage.formComponent.submit() +// await loginPage.validateErrorUX(); +// await loginPage.formComponent.errorComponent.hasMessage('Username is required'); +// }) - test('should not login with empty password', async({page}) => { - await loginPage.formComponent.fill(data.empty_password); - await loginPage.formComponent.submit() - await loginPage.validateErrorUX(); - await loginPage.formComponent.errorComponent.hasMessage('Password is required'); - }) +// test('should not login with empty password', async({page}) => { +// await loginPage.formComponent.fill(data.empty_password); +// await loginPage.formComponent.submit() +// await loginPage.validateErrorUX(); +// await loginPage.formComponent.errorComponent.hasMessage('Password is required'); +// }) - test('should not login with empty credential', async({page}) => { - await loginPage.formComponent.fill(data.empty_credential); - await loginPage.formComponent.submit() - await loginPage.validateErrorUX(); - await loginPage.formComponent.errorComponent.hasMessage('Username is required'); - }) -}) \ No newline at end of file +// test('should not login with empty credential', async({page}) => { +// await loginPage.formComponent.fill(data.empty_credential); +// await loginPage.formComponent.submit() +// await loginPage.validateErrorUX(); +// await loginPage.formComponent.errorComponent.hasMessage('Username is required'); +// }) +// }) \ No newline at end of file diff --git a/tests/e2e/menu.spec.ts b/tests/e2e/menu.spec.ts new file mode 100644 index 0000000..e4b89f8 --- /dev/null +++ b/tests/e2e/menu.spec.ts @@ -0,0 +1,47 @@ +import test, { expect } from "@playwright/test"; +import { InventoryPage } from "../pages/InventoryPage"; +import { InventoryItemPage } from "../pages/InventoryItemPage"; +import { IProduct, SortOptions } from "../fixtures/models"; +import data from '../fixtures/data/products.json'; + +let inventoryPage: InventoryPage; + +test.beforeEach( async ({page}) => { + inventoryPage = new InventoryPage(page); + await inventoryPage.visit(); +}); +test.describe('Menu features', () => { + test('Should open and close menu', async () => { + await inventoryPage.header.menu.isClosed(); + await inventoryPage.header.openMenu(); + await inventoryPage.header.menu.isOpened(); + await inventoryPage.header.menu.close(); + await inventoryPage.header.menu.isClosed(); + }); + + test('Should reset app state', async () => { + await inventoryPage.items[0].addToCart(); + await inventoryPage.header.cartCounter(1); + await inventoryPage.header.openMenu(); + await inventoryPage.header.menu.reset(); + await inventoryPage.header.cartCounter(0); + }) + + test('Should visit about', async () => { + await inventoryPage.header.openMenu(); + await inventoryPage.header.menu.visitAbout(); + }) + + test('Should visit All Items', async () => { + await inventoryPage.header.visitCart(); + await inventoryPage.header.openMenu(); + await inventoryPage.header.menu.visitItems(); + await inventoryPage.toBe(); + }) + + test('Should logout', async ({page}) => { + await inventoryPage.header.openMenu(); + await inventoryPage.header.menu.visitLogout(); + await expect(page).toHaveURL('/'); + }) +}) \ No newline at end of file diff --git a/tests/fixtures/dimensions.json b/tests/fixtures/dimensions.json new file mode 100644 index 0000000..e6763ec --- /dev/null +++ b/tests/fixtures/dimensions.json @@ -0,0 +1,38 @@ +{ + "24Inch": { + "width": 1920, + "height": 1200 + }, + "15Inch": { + "width": 1366, + "height": 768 + }, + "13Inch": { + "width": 1024, + "height": 800 + }, + "iphone4": { + "width": 320, + "height": 480 + }, + "iphone5": { + "width": 320, + "height": 568 + }, + "iphone7": { + "width": 375, + "height": 667 + }, + "iphoneX": { + "width": 375, + "height": 812 + }, + "iphoneXr": { + "width": 414, + "height": 896 + }, + "samsungS10": { + "width": 360, + "height": 760 + } +} \ No newline at end of file diff --git a/tests/pages/BasePage.ts b/tests/pages/BasePage.ts index a1bf33b..27e3297 100644 --- a/tests/pages/BasePage.ts +++ b/tests/pages/BasePage.ts @@ -20,6 +20,18 @@ export abstract class BasePage { await this.page.waitForLoadState('networkidle') } - abstract validateDefaultUX(); + abstract validateDefaultLayout(); + + validateViewportResize = async () => { + for (let width = this.page.viewportSize()!.width; width >= 320; width -= 320) { + await this.page.setViewportSize({ width, height: this.page.viewportSize()!.height }); + + const screenWidth = await this.page.evaluate(() => { + return document.documentElement.clientWidth; + }); + + expect(screenWidth).toBe(width); + } + } } \ No newline at end of file diff --git a/tests/pages/CartPage.ts b/tests/pages/CartPage.ts index f49c13b..690e1e2 100644 --- a/tests/pages/CartPage.ts +++ b/tests/pages/CartPage.ts @@ -35,7 +35,7 @@ export class CartPage extends BasePage{ this.locatorCheckoutButton = this.page.getByRole('button', { name: 'Checkout'}); } - validateDefaultUX = async () => { + validateDefaultLayout = async () => { await expect(this.locatorYourCart).toBeVisible(); await expect(this.locatorQty).toBeVisible(); await expect(this.locatorDescription).toBeVisible(); @@ -47,7 +47,7 @@ export class CartPage extends BasePage{ } } - validateEmptyUX = async () => { + validateEmptyLayout = async () => { await expect(this.locatorYourCart).toBeVisible(); await expect(this.locatorQty).toBeVisible(); await expect(this.locatorDescription).toBeVisible(); diff --git a/tests/pages/CheckoutCompletePage.ts b/tests/pages/CheckoutCompletePage.ts index 298182e..422243c 100644 --- a/tests/pages/CheckoutCompletePage.ts +++ b/tests/pages/CheckoutCompletePage.ts @@ -27,14 +27,14 @@ export class CheckoutCompletePage extends BasePage{ this.locatorHomeButton = this.page.getByRole('button', {name: 'Back Home'}); } - validateDefaultUX = async () => { + validateDefaultLayout = async () => { await expect(this.locatorCheckoutImg).toBeVisible(); await expect(this.locatorHeading).toBeVisible(); await expect(this.locatorDescription).toBeVisible(); await expect(this.locatorHomeButton).toBeVisible(); - await this.footer.validateDefaultUX(); - await this.header.validateDefaultUX(); + await this.footer.validateDefaultLayout(); + await this.header.validateDefaultLayout(); } backHome = async () => { diff --git a/tests/pages/CheckoutStepOnePage.ts b/tests/pages/CheckoutStepOnePage.ts index fcf3bfb..fc758fe 100644 --- a/tests/pages/CheckoutStepOnePage.ts +++ b/tests/pages/CheckoutStepOnePage.ts @@ -17,14 +17,14 @@ export class CheckoutStepOnePage extends BasePage{ this.form = new CheckoutFormComponent(this.page); } - validateDefaultUX = async () => { + validateDefaultLayout = async () => { await expect(this.locatorHeaderTitle).toBeVisible(); await expect(this.locatorCancelButton).toBeVisible(); - await this.form.validateDefaultUx(); + await this.form.validateDefaultLayout(); } - validateErrorUX = async () => { - await this.form.validateErrorUX(); + validateErrorLayout = async () => { + await this.form.validateErrorLayout(); } cancel = async () => { diff --git a/tests/pages/CheckoutStepTwoPage.ts b/tests/pages/CheckoutStepTwoPage.ts index 4ff92ec..ec60e51 100644 --- a/tests/pages/CheckoutStepTwoPage.ts +++ b/tests/pages/CheckoutStepTwoPage.ts @@ -51,7 +51,7 @@ export class CheckoutStepTwoPage extends BasePage{ this.locatorFinishButton = this.page.getByRole('button', { name: 'Finish'}); } - validateDefaultUX = async () => { + validateDefaultLayout = async () => { await expect(this.locatorHeaderTitle).toBeVisible(); await expect(this.locatorQty).toBeVisible(); await expect(this.locatorDescription).toBeVisible(); @@ -66,8 +66,8 @@ export class CheckoutStepTwoPage extends BasePage{ await expect(this.locatorCancelButton).toBeVisible(); await expect(this.locatorFinishButton).toBeVisible(); - await this.footer.validateDefaultUX(); - await this.header.validateDefaultUX(); + await this.footer.validateDefaultLayout(); + await this.header.validateDefaultLayout(); for(const product of this.products){ await product.validateDefaultUX(); diff --git a/tests/pages/InventoryItemPage.ts b/tests/pages/InventoryItemPage.ts index 977e798..ec60495 100644 --- a/tests/pages/InventoryItemPage.ts +++ b/tests/pages/InventoryItemPage.ts @@ -33,7 +33,7 @@ export class InventoryItemPage extends BasePage{ this.header = new HeaderComponent(this.page); } - validateDefaultUX = async () => { + validateDefaultLayout = async () => { await expect(this.locatorProductPhoto).toBeVisible(); await expect(this.locatorProductTitle).toBeVisible(); await expect(this.locatorProductDescription).toBeVisible(); @@ -41,11 +41,11 @@ export class InventoryItemPage extends BasePage{ await expect(this.locatorAddCartButton).toBeVisible(); await expect(this.locatorRemoveCartButton).not.toBeVisible(); await expect(this.locatorHeaderBackButton).toBeVisible(); - this.footer.validateDefaultUX(); - this.header.validateDefaultUX(); + this.footer.validateDefaultLayout(); + this.header.validateDefaultLayout(); } - validateRemoveUX = async () => { + validateRemoveLayout = async () => { await expect(this.locatorProductPhoto).toBeVisible(); await expect(this.locatorProductTitle).toBeVisible(); await expect(this.locatorProductDescription).toBeVisible(); @@ -54,8 +54,8 @@ export class InventoryItemPage extends BasePage{ await expect(this.locatorAddCartButton).not.toBeVisible(); await expect(this.locatorHeaderBackButton).toBeVisible(); - this.footer.validateDefaultUX(); - this.header.validateDefaultUX(); + this.footer.validateDefaultLayout(); + this.header.validateDefaultLayout(); } addToCart = async () => { diff --git a/tests/pages/InventoryPage.ts b/tests/pages/InventoryPage.ts index 3513ceb..f0b1b14 100644 --- a/tests/pages/InventoryPage.ts +++ b/tests/pages/InventoryPage.ts @@ -30,7 +30,7 @@ export class InventoryPage extends BasePage{ } } - validateDefaultUX = async () => { + validateDefaultLayout = async () => { await expect(this.locatorHeaderFilterSelect).toBeVisible(); await expect(this.locatorHeaderTitle).toBeVisible(); @@ -38,8 +38,8 @@ export class InventoryPage extends BasePage{ await item.validateDefaultUX (); } - await this.header.validateDefaultUX(); - await this.footer.validateDefaultUX(); + await this.header.validateDefaultLayout(); + await this.footer.validateDefaultLayout(); } sort = async (sort: SortOptions) => { diff --git a/tests/pages/LoginPage.ts b/tests/pages/LoginPage.ts index ed81184..c466217 100644 --- a/tests/pages/LoginPage.ts +++ b/tests/pages/LoginPage.ts @@ -21,7 +21,7 @@ export class LoginPage extends BasePage{ } - validateDefaultUX = async () => { + validateDefaultLayout = async () => { await expect(this.page.getByText('Swag Labs')).toBeVisible(); await expect(this.locatorUserNameList).toBeVisible(); @@ -29,10 +29,10 @@ export class LoginPage extends BasePage{ await expect(this.locatorPasswordList).toBeVisible(); await expect(this.locatorPasswordList).toContainText(this.passwordForAll); - await this.formComponent.validateDefaultUx(); + await this.formComponent.validateDefaultLayout(); } - validateErrorUX = async () => { + validateErrorLayout = async () => { await expect(this.page.getByText('Swag Labs')).toBeVisible(); await expect(this.locatorUserNameList).toBeVisible(); @@ -40,6 +40,6 @@ export class LoginPage extends BasePage{ await expect(this.locatorPasswordList).toBeVisible(); await expect(this.locatorPasswordList).toContainText(this.passwordForAll); - await this.formComponent.validateErrorUX(); + await this.formComponent.validateErrorLayout(); } } \ No newline at end of file diff --git a/tests/ui/cart.spec.ts b/tests/ui/cart.spec.ts new file mode 100644 index 0000000..792c8a3 --- /dev/null +++ b/tests/ui/cart.spec.ts @@ -0,0 +1,34 @@ +import { test, expect } from '@playwright/test'; +import { InventoryPage } from '../pages/InventoryPage'; +import { CartPage } from '../pages/CartPage'; +import data from '../fixtures/data/cart.json'; +import { CheckoutStepOnePage } from '../pages/CheckoutStepOnePage'; + +let inventoryPage: InventoryPage; +let cartPage: CartPage; + + +test.beforeEach(async ({page}) => { + inventoryPage = new InventoryPage(page); + cartPage = new CartPage(page, [data[1], data[2], data[3]]); + + await inventoryPage.visit(); + await inventoryPage.items[0].addToCart(); + await inventoryPage.items[2].addToCart(); + await inventoryPage.items[4].addToCart(); + await inventoryPage.header.visitCart(); + await cartPage.toBe(); + +}) + +test.describe('Cart UI', () => { + + test('Viewport should resize correctly @responsive', async () => { + await cartPage.validateViewportResize(); + }) + + test('Should have default Layout', async () => { + await cartPage.validateDefaultLayout(); + }) + +}); diff --git a/tests/ui/checkout.spec.ts b/tests/ui/checkout.spec.ts new file mode 100644 index 0000000..cc1b136 --- /dev/null +++ b/tests/ui/checkout.spec.ts @@ -0,0 +1,83 @@ +import test from "@playwright/test"; +import { CartPage } from "../pages/CartPage"; +import { InventoryPage } from "../pages/InventoryPage"; +import data from '../fixtures/data/cart.json'; +import dataCheckout from '../fixtures/data/checkout.json'; +import { CheckoutStepOnePage } from "../pages/CheckoutStepOnePage"; +import { CheckoutStepTwoPage } from "../pages/CheckoutStepTwoPage"; +import { CheckoutCompletePage } from "../pages/CheckoutCompletePage"; + +let inventoryPage: InventoryPage; +let cartPage: CartPage; +let checkoutOnePage: CheckoutStepOnePage; +let checkoutTwoPage: CheckoutStepTwoPage; +let checkoutCompletePage: CheckoutCompletePage; + +test.beforeEach(async ({page})=> { + inventoryPage = new InventoryPage(page); + checkoutOnePage = new CheckoutStepOnePage(page); + checkoutTwoPage = new CheckoutStepTwoPage(page, [data[1], data[2], data[3]]); + checkoutCompletePage = new CheckoutCompletePage(page); + + cartPage = new CartPage(page, [data[1], data[2], data[3]]); + + await inventoryPage.visit(); + await inventoryPage.items[0].addToCart(); + await inventoryPage.items[2].addToCart(); + await inventoryPage.items[4].addToCart(); + await inventoryPage.header.visitCart(); + await cartPage.checkout(); +}) + +test.describe('Checkout Step One UI', () => { + + test('Viewport should resize correctly @responsive', async () => { + await checkoutOnePage.validateViewportResize(); + }) + + test('Should have default UI', async () => { + await checkoutOnePage.validateDefaultLayout(); + }) + + test('Should have Error UI on invalid form', async () => { + await checkoutOnePage.form.submit(); + await checkoutOnePage.validateErrorLayout(); + }) + + test('Viewport should resize correctly', async () => { + await checkoutOnePage.validateViewportResize(); + }) +}); + +test.describe('Checkout Step Two UI', () => { + test('Viewport should resize correctly @responsive', async () => { + await checkoutTwoPage.validateViewportResize(); + }) + + test('Should have default UI', async () => { + await checkoutOnePage.form.fill(dataCheckout.success); + await checkoutOnePage.form.submit(); + await checkoutTwoPage.validateDefaultLayout(); + }) + + test('Viewport should resize correctly', async () => { + await checkoutTwoPage.validateViewportResize(); + }) +}); + +test.describe('Checkout Complete UI', () => { + test('Viewport should resize correctly @responsive', async () => { + await checkoutCompletePage.validateViewportResize(); + }) + + test('Should have default UI', async () => { + await checkoutOnePage.form.fill(dataCheckout.success); + await checkoutOnePage.form.submit(); + await checkoutTwoPage.finish(); + await checkoutCompletePage.validateDefaultLayout(); + }) + + test('Viewport should resize correctly', async () => { + await checkoutCompletePage.validateViewportResize(); + }) +}); \ No newline at end of file diff --git a/tests/ui/inventory-item.spec.ts b/tests/ui/inventory-item.spec.ts new file mode 100644 index 0000000..fd7cdd4 --- /dev/null +++ b/tests/ui/inventory-item.spec.ts @@ -0,0 +1,40 @@ +import test from "@playwright/test"; +import { InventoryPage } from "../pages/InventoryPage"; +import { InventoryItemPage } from "../pages/InventoryItemPage"; +import data from '../fixtures/data/products.json'; + +let inventoryPage: InventoryPage; +let inventoryItemInPage: InventoryItemPage; +let inventoryItemPage: InventoryItemPage; +const PROD_INDEX_IN_CART = 2; +const PROD_INDEX_OUT_CART = 1; + +test.beforeEach(async ({page}) => { + inventoryItemPage = new InventoryItemPage(page, data.az[PROD_INDEX_OUT_CART]); + inventoryItemInPage = new InventoryItemPage(page, data.az[PROD_INDEX_IN_CART]); + inventoryPage = new InventoryPage(page); + inventoryPage.visit(); + await inventoryPage.items[PROD_INDEX_IN_CART].addToCart(); +}); + +test.describe('Inventory Item UI', () => { + test('Viewport should resize correctly @responsive', async () => { + await inventoryItemPage.validateViewportResize(); + }) + + test('Should have default Layout when accessing a product that is not added', async () => { + await inventoryPage.items[PROD_INDEX_OUT_CART].openDetailsClickingOnPhoto(); + await inventoryItemPage.validateDefaultLayout(); + + + }); + + test('Should have Remove-Layout when accessing a product that is added', async () => { + await inventoryPage.items[PROD_INDEX_IN_CART].openDetailsClickingOnPhoto(); + await inventoryItemInPage.validateRemoveLayout(); + }); + + test('Viewport should resize correctly', async () => { + await inventoryItemInPage.validateViewportResize(); + }) +}); diff --git a/tests/ui/inventory.spec.ts b/tests/ui/inventory.spec.ts new file mode 100644 index 0000000..4beafa8 --- /dev/null +++ b/tests/ui/inventory.spec.ts @@ -0,0 +1,35 @@ +import test, { expect } from "@playwright/test"; +import { InventoryPage } from "../pages/InventoryPage"; +import { InventoryItemPage } from "../pages/InventoryItemPage"; +import { IProduct, SortOptions } from "../fixtures/models"; +import data from '../fixtures/data/products.json'; + +let inventoryPage: InventoryPage; + +test.beforeEach( async ({page}) => { + inventoryPage = new InventoryPage(page); + await inventoryPage.visit(); +}); + +test.describe('Inventory UI', () => { + test('Viewport should resize correctly @responsive', async () => { + await inventoryPage.validateViewportResize(); + }) + + test('Should have default Layout', async ({page}) => { + await inventoryPage.validateDefaultLayout(); + }) + + test('Should alternate Add To Cart button and Remove button when add/remove item to/from cart', async () => { + const index = Math.floor(Math.random()*inventoryPage.items.length); + await inventoryPage.items[index].addToCart(); + await inventoryPage.items[index].validateRemoveUX(); + await inventoryPage.items[index].removeFromCart(); + await inventoryPage.items[index].validateAddLayout(); + }) + + test('Viewport should resize correctly', async () => { + await inventoryPage.validateViewportResize(); + }) + +}) \ No newline at end of file diff --git a/tests/ui/login.spec.ts b/tests/ui/login.spec.ts new file mode 100644 index 0000000..ac6a354 --- /dev/null +++ b/tests/ui/login.spec.ts @@ -0,0 +1,32 @@ +import { test } from '@playwright/test'; +import { LoginPage } from '../pages/LoginPage'; +import data from '../fixtures/data/users.json'; +import { InventoryPage } from '../pages/InventoryPage'; +let loginPage: LoginPage; + +test.use({ storageState: { cookies: [], origins: [] } }); + +test.beforeEach(async ({page}) => { + loginPage = new LoginPage(page); + await loginPage.visit(); + await loginPage.toBe(); +}) + +test.describe('login UI', () => { + test('Viewport should resize correctly @responsive', async () => { + await loginPage.validateViewportResize(); + }) + + test('should have default Layout on start', async ({page}) => { + await loginPage.validateDefaultLayout(); + }) + + test('should have Error Layout on invalid form', async ({page}) => { + await loginPage.formComponent.submit() + await loginPage.validateErrorLayout(); + }) + + test('Viewport should resize correctly', async () => { + await loginPage.validateViewportResize(); + }) +}); diff --git a/tests/ui/menu.spec.ts b/tests/ui/menu.spec.ts new file mode 100644 index 0000000..a40c543 --- /dev/null +++ b/tests/ui/menu.spec.ts @@ -0,0 +1,21 @@ +import test, { expect } from "@playwright/test"; +import { InventoryPage } from "../pages/InventoryPage"; +import { InventoryItemPage } from "../pages/InventoryItemPage"; +import { IProduct, SortOptions } from "../fixtures/models"; +import data from '../fixtures/data/products.json'; + +let inventoryPage: InventoryPage; + +test.beforeEach( async ({page}) => { + inventoryPage = new InventoryPage(page); + await inventoryPage.visit(); +}); + +test.describe('Menu, Header, Footer', () => { + test('Should have default UI', async () => { + await inventoryPage.header.validateDefaultLayout(); + await inventoryPage.footer.validateDefaultLayout(); + await inventoryPage.header.openMenu(); + await inventoryPage.header.menu.validateDefaultLayout(); + }); +}) diff --git a/tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-linux.png b/tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-linux.png deleted file mode 100644 index 6fed7a5..0000000 Binary files a/tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-linux.png and /dev/null differ diff --git a/tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-win32.png b/tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-on-Desktop-Chrome-win32.png similarity index 100% rename from tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-win32.png rename to tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-on-Desktop-Chrome-win32.png diff --git a/tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-on-Pixel-5-win32.png b/tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-on-Pixel-5-win32.png new file mode 100644 index 0000000..a97876b Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-on-Pixel-5-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-on-iPhone-12-win32.png b/tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-on-iPhone-12-win32.png new file mode 100644 index 0000000..d4f9767 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/cartPage-empty-visual-on-iPhone-12-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/cartPage-visual-linux.png b/tests/visual/visual.spec.ts-snapshots/cartPage-visual-linux.png deleted file mode 100644 index 96c7284..0000000 Binary files a/tests/visual/visual.spec.ts-snapshots/cartPage-visual-linux.png and /dev/null differ diff --git a/tests/visual/visual.spec.ts-snapshots/cartPage-visual-win32.png b/tests/visual/visual.spec.ts-snapshots/cartPage-visual-on-Desktop-Chrome-win32.png similarity index 100% rename from tests/visual/visual.spec.ts-snapshots/cartPage-visual-win32.png rename to tests/visual/visual.spec.ts-snapshots/cartPage-visual-on-Desktop-Chrome-win32.png diff --git a/tests/visual/visual.spec.ts-snapshots/cartPage-visual-on-Pixel-5-win32.png b/tests/visual/visual.spec.ts-snapshots/cartPage-visual-on-Pixel-5-win32.png new file mode 100644 index 0000000..46d497b Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/cartPage-visual-on-Pixel-5-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/cartPage-visual-on-iPhone-12-win32.png b/tests/visual/visual.spec.ts-snapshots/cartPage-visual-on-iPhone-12-win32.png new file mode 100644 index 0000000..662e83b Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/cartPage-visual-on-iPhone-12-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-linux.png b/tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-linux.png deleted file mode 100644 index d664314..0000000 Binary files a/tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-linux.png and /dev/null differ diff --git a/tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-win32.png b/tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-on-Desktop-Chrome-win32.png similarity index 100% rename from tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-win32.png rename to tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-on-Desktop-Chrome-win32.png diff --git a/tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-on-Pixel-5-win32.png b/tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-on-Pixel-5-win32.png new file mode 100644 index 0000000..60deb6a Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-on-Pixel-5-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-on-iPhone-12-win32.png b/tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-on-iPhone-12-win32.png new file mode 100644 index 0000000..186aef4 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/checkoutPage-complete-visual-on-iPhone-12-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-linux.png b/tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-linux.png deleted file mode 100644 index 7cedf0e..0000000 Binary files a/tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-linux.png and /dev/null differ diff --git a/tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-win32.png b/tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-on-Desktop-Chrome-win32.png similarity index 100% rename from tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-win32.png rename to tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-on-Desktop-Chrome-win32.png diff --git a/tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-on-Pixel-5-win32.png b/tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-on-Pixel-5-win32.png new file mode 100644 index 0000000..fcb4da3 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-on-Pixel-5-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-on-iPhone-12-win32.png b/tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-on-iPhone-12-win32.png new file mode 100644 index 0000000..8cbad62 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/checkoutPage-one-visual-on-iPhone-12-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-linux.png b/tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-linux.png deleted file mode 100644 index 83da7de..0000000 Binary files a/tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-linux.png and /dev/null differ diff --git a/tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-win32.png b/tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-on-Desktop-Chrome-win32.png similarity index 100% rename from tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-win32.png rename to tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-on-Desktop-Chrome-win32.png diff --git a/tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-on-Pixel-5-win32.png b/tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-on-Pixel-5-win32.png new file mode 100644 index 0000000..a40c8a7 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-on-Pixel-5-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-on-iPhone-12-win32.png b/tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-on-iPhone-12-win32.png new file mode 100644 index 0000000..89b4de4 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/checkoutPage-two-visual-on-iPhone-12-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-linux.png b/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-linux.png deleted file mode 100644 index a579408..0000000 Binary files a/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-linux.png and /dev/null differ diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-win32.png b/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-on-Desktop-Chrome-win32.png similarity index 100% rename from tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-win32.png rename to tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-on-Desktop-Chrome-win32.png diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-on-Pixel-5-win32.png b/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-on-Pixel-5-win32.png new file mode 100644 index 0000000..814d133 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-on-Pixel-5-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-on-iPhone-12-win32.png b/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-on-iPhone-12-win32.png new file mode 100644 index 0000000..b6f06be Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-added-visual-on-iPhone-12-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-linux.png b/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-linux.png deleted file mode 100644 index 292fcd8..0000000 Binary files a/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-linux.png and /dev/null differ diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-win32.png b/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-on-Desktop-Chrome-win32.png similarity index 100% rename from tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-win32.png rename to tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-on-Desktop-Chrome-win32.png diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-on-Pixel-5-win32.png b/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-on-Pixel-5-win32.png new file mode 100644 index 0000000..3372f9c Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-on-Pixel-5-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-on-iPhone-12-win32.png b/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-on-iPhone-12-win32.png new file mode 100644 index 0000000..d7c05d5 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/inventoryItemPage-visual-on-iPhone-12-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-linux.png b/tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-linux.png deleted file mode 100644 index 81943ce..0000000 Binary files a/tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-linux.png and /dev/null differ diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-win32.png b/tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-on-Desktop-Chrome-win32.png similarity index 100% rename from tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-win32.png rename to tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-on-Desktop-Chrome-win32.png diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-on-Pixel-5-win32.png b/tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-on-Pixel-5-win32.png new file mode 100644 index 0000000..e67a5d7 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-on-Pixel-5-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-on-iPhone-12-win32.png b/tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-on-iPhone-12-win32.png new file mode 100644 index 0000000..5d6076e Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/inventoryPage-added-visual-on-iPhone-12-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-linux.png b/tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-linux.png deleted file mode 100644 index 2cf9096..0000000 Binary files a/tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-linux.png and /dev/null differ diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-win32.png b/tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-on-Desktop-Chrome-win32.png similarity index 100% rename from tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-win32.png rename to tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-on-Desktop-Chrome-win32.png diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-on-Pixel-5-win32.png b/tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-on-Pixel-5-win32.png new file mode 100644 index 0000000..9fb3677 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-on-Pixel-5-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-on-iPhone-12-win32.png b/tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-on-iPhone-12-win32.png new file mode 100644 index 0000000..2efa938 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/inventoryPage-visual-on-iPhone-12-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-linux.png b/tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-linux.png deleted file mode 100644 index 34f096f..0000000 Binary files a/tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-linux.png and /dev/null differ diff --git a/tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-win32.png b/tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-on-Desktop-Chrome-win32.png similarity index 100% rename from tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-win32.png rename to tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-on-Desktop-Chrome-win32.png diff --git a/tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-on-Pixel-5-win32.png b/tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-on-Pixel-5-win32.png new file mode 100644 index 0000000..f124e56 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-on-Pixel-5-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-on-iPhone-12-win32.png b/tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-on-iPhone-12-win32.png new file mode 100644 index 0000000..d276eb6 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/loginPage-error-visual-on-iPhone-12-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/loginPage-visual-linux.png b/tests/visual/visual.spec.ts-snapshots/loginPage-visual-linux.png deleted file mode 100644 index 0bf2a80..0000000 Binary files a/tests/visual/visual.spec.ts-snapshots/loginPage-visual-linux.png and /dev/null differ diff --git a/tests/visual/visual.spec.ts-snapshots/loginPage-visual-win32.png b/tests/visual/visual.spec.ts-snapshots/loginPage-visual-on-Desktop-Chrome-win32.png similarity index 100% rename from tests/visual/visual.spec.ts-snapshots/loginPage-visual-win32.png rename to tests/visual/visual.spec.ts-snapshots/loginPage-visual-on-Desktop-Chrome-win32.png diff --git a/tests/visual/visual.spec.ts-snapshots/loginPage-visual-on-Pixel-5-win32.png b/tests/visual/visual.spec.ts-snapshots/loginPage-visual-on-Pixel-5-win32.png new file mode 100644 index 0000000..4eaab07 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/loginPage-visual-on-Pixel-5-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/loginPage-visual-on-iPhone-12-win32.png b/tests/visual/visual.spec.ts-snapshots/loginPage-visual-on-iPhone-12-win32.png new file mode 100644 index 0000000..965e19f Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/loginPage-visual-on-iPhone-12-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/menu-visual-linux.png b/tests/visual/visual.spec.ts-snapshots/menu-visual-linux.png deleted file mode 100644 index 4b6e1ca..0000000 Binary files a/tests/visual/visual.spec.ts-snapshots/menu-visual-linux.png and /dev/null differ diff --git a/tests/visual/visual.spec.ts-snapshots/menu-visual-win32.png b/tests/visual/visual.spec.ts-snapshots/menu-visual-on-Desktop-Chrome-win32.png similarity index 100% rename from tests/visual/visual.spec.ts-snapshots/menu-visual-win32.png rename to tests/visual/visual.spec.ts-snapshots/menu-visual-on-Desktop-Chrome-win32.png diff --git a/tests/visual/visual.spec.ts-snapshots/menu-visual-on-Pixel-5-win32.png b/tests/visual/visual.spec.ts-snapshots/menu-visual-on-Pixel-5-win32.png new file mode 100644 index 0000000..d5c6bda Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/menu-visual-on-Pixel-5-win32.png differ diff --git a/tests/visual/visual.spec.ts-snapshots/menu-visual-on-iPhone-12-win32.png b/tests/visual/visual.spec.ts-snapshots/menu-visual-on-iPhone-12-win32.png new file mode 100644 index 0000000..31497f2 Binary files /dev/null and b/tests/visual/visual.spec.ts-snapshots/menu-visual-on-iPhone-12-win32.png differ diff --git a/ui.md b/ui.md new file mode 100644 index 0000000..ff86761 --- /dev/null +++ b/ui.md @@ -0,0 +1,92 @@ +# User Interface (UI) Tests + +This set of UI tests, located in the `ui/` and `visual/` directories, is designed to thoroughly evaluate various aspects of the user interface, including layout, usability, responsiveness, and visual elements. + +## UI Test Scenarios + +### login.spec.ts + +1. **Viewport should resize correctly** + - Description: Simulate resizing the browser window and check if the page responds correctly, dynamically adapting to the window size. + +1. **Should Have Default Layout on Start** + - Description: Confirm that the login page exhibits the expected default layout upon initial loading. + - Steps: Access the login page and verify the layout conforms to the default design. + +1. **Should Have Error Layout on Invalid Form** + - Description: Validate that the login page switches to an error-specific layout when an invalid form is submitted. + - Steps: Submit a login form with incorrect credentials and ensure the error layout is displayed. + +### inventory.spec.ts + +1. **Viewport should resize correctly** + - Description: Simulate resizing the browser window and check if the page responds correctly, dynamically adapting to the window size. + +1. **Should Have Default Layout** + - Description: Verify that the inventory page maintains the default layout upon initial access. + - Steps: Navigate to the inventory page and confirm adherence to the default design. + +1. **Should Alternate Add To Cart and Remove Buttons** + - Description: Confirm that the "Add to Cart" and "Remove" buttons on the inventory page alternate their visibility and layout when items are added or removed from the cart. + - Steps: Add an item to the cart and verify the change in button layout. Then, remove the item and confirm the reversal of button layout. + +1. **Viewport should resize correctly** + - Description: Simulate resizing the browser window and check if the page responds correctly, dynamically adapting to the window size. + +### inventoryItem.spec.ts + +1. **Viewport should resize correctly** + - Description: Simulate resizing the browser window and check if the page responds correctly, dynamically adapting to the window size. + +1. **Should Have Default Layout When Accessing a Product That is Not Added** + - Description: Ensure that the product-specific page displays the default layout when accessing a product that has not been added to the cart. + - Steps: Access the detailed view of a product not in the cart and validate the default layout. + +1. **Should Have Remove Layout When Accessing a Product That is Added** + - Description: Confirm that the product-specific page displays a layout with the option to remove the product when accessing an item already added to the cart. + - Steps: Add a product to the cart, then access its detailed view and verify the presence of the remove-specific layout. + +1. **Viewport should resize correctly** + - Description: Simulate resizing the browser window and check if the page responds correctly, dynamically adapting to the window size. + +### cart.spec.ts + +1. **Viewport should resize correctly** + - Description: Simulate resizing the browser window and check if the page responds correctly, dynamically adapting to the window size. + +1. **Should Have Default Layout** + - Description: Confirm that the cart page displays the default layout upon navigation. + - Steps: Navigate to the cart and validate the default layout. + +1. **Viewport should resize correctly** + - Description: Simulate resizing the browser window and check if the page responds correctly, dynamically adapting to the window size. + +### checkout.spec.ts + +1. **Viewport should resize correctly** + - Description: Simulate resizing the browser window and check if the page responds correctly, dynamically adapting to the window size. + +1. **Checkout Step One Should Have Default Layout** + - Description: Validate that the first step of the checkout process displays the default layout. + - Steps: Initiate the checkout process and verify the layout on the first step. + +1. **Checkout Step One Should Have Error Layout on Invalid Form** + - Description: Confirm that the first step of the checkout process switches to an error-specific layout when an invalid form is submitted. + - Steps: Submit an incomplete or invalid form during the first step of checkout and ensure the error layout is displayed. + +1. **Checkout Step Two Should Have Default Layout** + - Description: Validate that the second step of the checkout process displays the default layout. + - Steps: Progress to the second step of checkout and verify the layout. + +1. **Checkout Complete Should Have Default Layout** + - Description: Confirm that the completion page of the checkout process exhibits the default layout. + - Steps: Complete the checkout process and validate the default layout on the completion page. + +1. **Viewport should resize correctly** + - Description: Simulate resizing the browser window and check if the page responds correctly, dynamically adapting to the window size. + +### menu.spec.ts + +1. **Menu, Header, Footer Should Have Default Layout** + - Description: Validate that the menu, header, and footer components maintain the default layout. + - Steps: Navigate through menu options and access different sections to ensure the default layout is consistent.