Files
cbsnexora/playwright/tests/login-responsive.spec.ts
T

284 lines
9.8 KiB
TypeScript

/**
* Copyright since 2025 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
import { test, expect } from '@playwright/test';
import { LoginPage } from 'playwright/pages/login.page';
/**
* Login Responsive Layout Tests
*
* This test suite validates that the login page displays correctly
* and fills the viewport at different screen sizes.
*/
const VIEWPORTS = {
mobile: { width: 375, height: 667 }, // iPhone SE
mobileLandscape: { width: 667, height: 375 },
tablet: { width: 768, height: 1024 }, // iPad
desktop: { width: 1280, height: 720 }, // Desktop
largeDesktop: { width: 1920, height: 1080 } // Full HD
};
test.describe('Login Page - Responsive Layout', () => {
let loginPage: LoginPage;
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
await loginPage.navigate();
});
test('should fill viewport on mobile portrait (375x667)', async ({ page }) => {
await page.setViewportSize(VIEWPORTS.mobile);
// Verify the login form is visible
await loginPage.assertOnLoginPage();
// Check login wrapper fills viewport
const loginWrapper = loginPage.divLocator('.login-wrapper');
await expect(loginWrapper).toBeVisible();
const wrapperBox = await loginWrapper.boundingBox();
expect(wrapperBox?.height).toBeGreaterThanOrEqual(VIEWPORTS.mobile.height - 10);
// Check login panel exists and is visible
const loginPanel = loginPage.divLocator('.login-panel');
await expect(loginPanel).toBeVisible();
// Check all essential elements are visible
await expect(loginPage.divLocator('.logo-section')).toBeVisible();
await expect(loginPage.divLocator('.form-section')).toBeVisible();
await expect(loginPage.divLocator('.login-footer')).toBeVisible();
// Verify no horizontal scroll
const bodyWidth = await page.evaluate(() => document.body.scrollWidth);
expect(bodyWidth).toBeLessThanOrEqual(VIEWPORTS.mobile.width + 1);
});
test('should fill viewport on tablet (768x1024)', async ({ page }) => {
await page.setViewportSize(VIEWPORTS.tablet);
// Verify the login form is visible
await loginPage.assertOnLoginPage();
const loginWrapper = loginPage.divLocator('.login-wrapper');
await expect(loginWrapper).toBeVisible();
const wrapperBox = await loginWrapper.boundingBox();
expect(wrapperBox?.height).toBeGreaterThanOrEqual(VIEWPORTS.tablet.height - 10);
// On tablet, hero panel should be hidden
const heroPanel = loginPage.divLocator('.hero-panel');
await expect(heroPanel).not.toBeVisible();
// Login panel should be visible
const loginPanel = loginPage.divLocator('.login-panel');
await expect(loginPanel).toBeVisible();
// All sections should be visible
await expect(loginPage.divLocator('.logo-section')).toBeVisible();
await expect(loginPage.divLocator('.form-section')).toBeVisible();
});
test('should fill viewport on desktop (1280x720)', async ({ page }) => {
await page.setViewportSize(VIEWPORTS.desktop);
// Verify the login form is visible
await loginPage.assertOnLoginPage();
const loginWrapper = loginPage.divLocator('.login-wrapper');
await expect(loginWrapper).toBeVisible();
const wrapperBox = await loginWrapper.boundingBox();
expect(wrapperBox?.height).toBeGreaterThanOrEqual(VIEWPORTS.desktop.height - 10);
// On desktop, hero panel should be visible
const heroPanel = loginPage.divLocator('.hero-panel');
await expect(heroPanel).toBeVisible();
// Login panel should be visible
const loginPanel = loginPage.divLocator('.login-panel');
await expect(loginPanel).toBeVisible();
// Login card should be centered
const loginCard = loginPage.divLocator('.login-card');
await expect(loginCard).toBeVisible();
});
test('should display all content without scrolling on desktop', async ({ page }) => {
await page.setViewportSize(VIEWPORTS.desktop);
// Verify the login form is visible
await loginPage.assertOnLoginPage();
// Check if login card content is fully visible
const loginCard = loginPage.divLocator('.login-card');
const cardBox = await loginCard.boundingBox();
// Logo should be visible
const logo = loginPage.divLocator('.logo-image');
const logoBox = await logo.boundingBox();
expect(logoBox).toBeTruthy();
// Username input should be visible
const usernameInput = page.locator('input[formcontrolname="username"]');
const usernameBox = await usernameInput.boundingBox();
expect(usernameBox).toBeTruthy();
// Password input should be visible
const passwordInput = page.locator('input[formcontrolname="password"]');
const passwordBox = await passwordInput.boundingBox();
expect(passwordBox).toBeTruthy();
// Login button should be visible
const loginButton = page.locator('mifosx-m3-button[type="submit"]');
const buttonBox = await loginButton.boundingBox();
expect(buttonBox).toBeTruthy();
// Resources section should be visible
const resourcesSection = page.locator('.resources-section');
const resourcesBox = await resourcesSection.boundingBox();
expect(resourcesBox).toBeTruthy();
// Footer should be visible
const footer = loginPage.divLocator('.login-footer');
const footerBox = await footer.boundingBox();
expect(footerBox).toBeTruthy();
});
test('should handle small mobile screens (375x667) with all content visible', async ({ page }) => {
await page.setViewportSize(VIEWPORTS.mobile);
// Verify the login form is visible
await loginPage.assertOnLoginPage();
// Scroll to bottom to ensure footer is accessible
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
// Footer should be visible after scroll
const footer = loginPage.divLocator('.login-footer');
await expect(footer).toBeVisible();
// Scroll back to top
await page.evaluate(() => window.scrollTo(0, 0));
// Logo and form should be visible at top
await expect(loginPage.divLocator('.logo-section')).toBeVisible();
await expect(loginPage.divLocator('.form-section')).toBeVisible();
});
test('should maintain proper spacing between elements on all viewports', async ({ page }) => {
const viewports = [
VIEWPORTS.mobile,
VIEWPORTS.tablet,
VIEWPORTS.desktop
];
for (const viewport of viewports) {
await page.setViewportSize(viewport);
// Verify the login form is visible
await loginPage.assertOnLoginPage();
const logo = loginPage.divLocator('.logo-section');
const form = loginPage.divLocator('.form-section');
// All sections should be visible
await expect(logo).toBeVisible();
await expect(form).toBeVisible();
if (viewport.width > 1024) {
const resources = loginPage.divLocator('.resources-section');
await expect(resources).toBeVisible();
}
// Get bounding boxes
const logoBox = await logo.boundingBox();
const formBox = await form.boundingBox();
// Form should be below logo
if (logoBox && formBox) {
expect(formBox.y).toBeGreaterThan(logoBox.y + logoBox.height);
}
}
});
test('should not have horizontal overflow on any viewport', async ({ page }) => {
const viewports = [
VIEWPORTS.mobile,
VIEWPORTS.tablet,
VIEWPORTS.desktop
];
for (const viewport of viewports) {
await page.setViewportSize(viewport);
await page.goto('http://localhost:4200/login');
await page.waitForLoadState('networkidle');
// Check no horizontal scroll
const hasHorizontalScroll = await page.evaluate(() => {
return document.body.scrollWidth > window.innerWidth;
});
expect(hasHorizontalScroll).toBe(false);
}
});
test('should center login card vertically on desktop', async ({ page }) => {
await page.setViewportSize(VIEWPORTS.desktop);
// Verify the login form is visible
await loginPage.assertOnLoginPage();
const loginCard = page.locator('.login-card');
const cardBox = await loginCard.boundingBox();
const viewportHeight = VIEWPORTS.desktop.height;
// Card should be roughly centered (with some tolerance)
if (cardBox) {
const cardCenter = cardBox.y + cardBox.height / 2;
const viewportCenter = viewportHeight / 2;
// Allow 100px tolerance for header/footer
expect(Math.abs(cardCenter - viewportCenter)).toBeLessThan(150);
}
});
test('should show all form fields on mobile', async ({ page }) => {
await page.setViewportSize(VIEWPORTS.mobile);
// Verify the login form is visible
await loginPage.assertOnLoginPage();
// Username field
const usernameField = page.locator('mat-form-field').filter({ hasText: 'Username' });
await expect(usernameField).toBeVisible();
// Password field
const passwordField = page.locator('mat-form-field').filter({ hasText: 'Password' });
await expect(passwordField).toBeVisible();
// Login button
const loginButton = page.locator('mifosx-m3-button[type="submit"]');
await expect(loginButton).toBeVisible();
});
test('should show logo on all screen sizes', async ({ page }) => {
const viewports = [
VIEWPORTS.mobile,
VIEWPORTS.tablet,
VIEWPORTS.desktop
];
for (const viewport of viewports) {
await page.setViewportSize(viewport);
// Verify the login form is visible
await loginPage.assertOnLoginPage();
const logo = page.locator('.logo-image');
await expect(logo).toBeVisible();
// Logo should have appropriate size
const logoBox = await logo.boundingBox();
expect(logoBox?.width).toBeGreaterThan(0);
expect(logoBox?.height).toBeGreaterThan(0);
}
});
});