mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 01:01:39 -05:00
308 lines
11 KiB
JavaScript
308 lines
11 KiB
JavaScript
import { test, expect } from '@playwright/test';
|
|
import { closeOnboardingModal } from '../helpers/navigation.js';
|
|
|
|
/**
|
|
* Calendar Panel Tests
|
|
*
|
|
* Tests for the calendar panel control that allows users to navigate between
|
|
* different years and months. The panel is opened via the "Toggle Panel" button
|
|
* in the top-right corner of the map.
|
|
*/
|
|
|
|
test.describe('Calendar Panel', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/map');
|
|
await closeOnboardingModal(page);
|
|
|
|
// Wait for map to be fully loaded
|
|
await page.waitForSelector('.leaflet-container', { state: 'visible', timeout: 10000 });
|
|
await page.waitForTimeout(2000); // Wait for all controls to be initialized
|
|
});
|
|
|
|
/**
|
|
* Helper function to find and click the calendar toggle button
|
|
*/
|
|
async function clickCalendarButton(page) {
|
|
// The calendar button is the "Toggle Panel" button with a calendar icon
|
|
// It's the third button in the top-right control stack (after Select Area and Add Visit)
|
|
const calendarButton = await page.locator('button.toggle-panel-button').first();
|
|
await expect(calendarButton).toBeVisible({ timeout: 5000 });
|
|
await calendarButton.click();
|
|
await page.waitForTimeout(500); // Wait for panel animation
|
|
}
|
|
|
|
/**
|
|
* Helper function to check if panel is visible
|
|
*/
|
|
async function isPanelVisible(page) {
|
|
const panel = page.locator('.leaflet-right-panel');
|
|
const isVisible = await panel.isVisible().catch(() => false);
|
|
if (!isVisible) return false;
|
|
|
|
const displayStyle = await panel.evaluate(el => el.style.display);
|
|
return displayStyle !== 'none';
|
|
}
|
|
|
|
test('should open calendar panel on first click', async ({ page }) => {
|
|
// Verify panel is not visible initially
|
|
const initiallyVisible = await isPanelVisible(page);
|
|
expect(initiallyVisible).toBe(false);
|
|
|
|
// Click calendar button
|
|
await clickCalendarButton(page);
|
|
|
|
// Verify panel is now visible
|
|
const panelVisible = await isPanelVisible(page);
|
|
expect(panelVisible).toBe(true);
|
|
|
|
// Verify panel contains expected elements
|
|
const yearSelect = page.locator('#year-select');
|
|
await expect(yearSelect).toBeVisible();
|
|
|
|
const monthsGrid = page.locator('#months-grid');
|
|
await expect(monthsGrid).toBeVisible();
|
|
|
|
// Verify "Whole year" link is present
|
|
const wholeYearLink = page.locator('#whole-year-link');
|
|
await expect(wholeYearLink).toBeVisible();
|
|
});
|
|
|
|
test('should close calendar panel on second click', async ({ page }) => {
|
|
// Open panel
|
|
await clickCalendarButton(page);
|
|
await page.waitForTimeout(300);
|
|
|
|
// Verify panel is visible
|
|
let panelVisible = await isPanelVisible(page);
|
|
expect(panelVisible).toBe(true);
|
|
|
|
// Click button again to close
|
|
await clickCalendarButton(page);
|
|
await page.waitForTimeout(300);
|
|
|
|
// Verify panel is hidden
|
|
panelVisible = await isPanelVisible(page);
|
|
expect(panelVisible).toBe(false);
|
|
});
|
|
|
|
test('should allow year selection', async ({ page }) => {
|
|
// Open panel
|
|
await clickCalendarButton(page);
|
|
|
|
// Wait for year select to be populated (it loads from API)
|
|
await page.waitForTimeout(2000);
|
|
|
|
const yearSelect = page.locator('#year-select');
|
|
await expect(yearSelect).toBeVisible();
|
|
|
|
// Get available years
|
|
const options = await yearSelect.locator('option:not([disabled])').all();
|
|
|
|
// Should have at least one year available
|
|
expect(options.length).toBeGreaterThan(0);
|
|
|
|
// Select the first available year
|
|
const firstYearOption = options[0];
|
|
const yearValue = await firstYearOption.getAttribute('value');
|
|
|
|
await yearSelect.selectOption(yearValue);
|
|
|
|
// Verify year was selected
|
|
const selectedValue = await yearSelect.inputValue();
|
|
expect(selectedValue).toBe(yearValue);
|
|
});
|
|
|
|
test('should navigate to month when clicking month button', async ({ page }) => {
|
|
// Open panel
|
|
await clickCalendarButton(page);
|
|
|
|
// Wait for months to load
|
|
await page.waitForTimeout(3000);
|
|
|
|
// Select year 2024 (which has October data in demo)
|
|
const yearSelect = page.locator('#year-select');
|
|
await yearSelect.selectOption('2024');
|
|
await page.waitForTimeout(500);
|
|
|
|
// Find October button (demo data has October 2024)
|
|
const octoberButton = page.locator('#months-grid a[data-month-name="Oct"]');
|
|
await expect(octoberButton).toBeVisible({ timeout: 5000 });
|
|
|
|
// Verify October is enabled (not disabled)
|
|
const isDisabled = await octoberButton.evaluate(el => el.classList.contains('disabled'));
|
|
expect(isDisabled).toBe(false);
|
|
|
|
// Verify button is clickable
|
|
const pointerEvents = await octoberButton.evaluate(el => el.style.pointerEvents);
|
|
expect(pointerEvents).not.toBe('none');
|
|
|
|
// Get the expected href before clicking
|
|
const expectedHref = await octoberButton.getAttribute('href');
|
|
expect(expectedHref).toBeTruthy();
|
|
const decodedHref = decodeURIComponent(expectedHref);
|
|
|
|
expect(decodedHref).toContain('map?');
|
|
expect(decodedHref).toContain('start_at=2024-10-01T00:00');
|
|
expect(decodedHref).toContain('end_at=2024-10-31T23:59');
|
|
|
|
// Click the month button and wait for navigation
|
|
await Promise.all([
|
|
page.waitForURL('**/map**', { timeout: 10000 }),
|
|
octoberButton.click()
|
|
]);
|
|
|
|
// Wait for page to settle
|
|
await page.waitForLoadState('networkidle', { timeout: 10000 });
|
|
|
|
// Verify we navigated to the map page
|
|
expect(page.url()).toContain('/map');
|
|
|
|
// Verify map loaded with data
|
|
await page.waitForSelector('.leaflet-container', { state: 'visible', timeout: 10000 });
|
|
});
|
|
|
|
test('should navigate to whole year when clicking "Whole year" button', async ({ page }) => {
|
|
// Open panel
|
|
await clickCalendarButton(page);
|
|
|
|
// Wait for panel to load
|
|
await page.waitForTimeout(2000);
|
|
|
|
const wholeYearLink = page.locator('#whole-year-link');
|
|
await expect(wholeYearLink).toBeVisible();
|
|
|
|
// Get the href and decode it
|
|
const href = await wholeYearLink.getAttribute('href');
|
|
expect(href).toBeTruthy();
|
|
const decodedHref = decodeURIComponent(href);
|
|
|
|
expect(decodedHref).toContain('map?');
|
|
expect(decodedHref).toContain('start_at=');
|
|
expect(decodedHref).toContain('end_at=');
|
|
|
|
// Href should contain full year dates (01-01 to 12-31)
|
|
expect(decodedHref).toContain('-01-01T00:00');
|
|
expect(decodedHref).toContain('-12-31T23:59');
|
|
|
|
// Store the expected year from the href
|
|
const yearMatch = decodedHref.match(/(\d{4})-01-01/);
|
|
expect(yearMatch).toBeTruthy();
|
|
const expectedYear = yearMatch[1];
|
|
|
|
// Click the link and wait for navigation
|
|
await Promise.all([
|
|
page.waitForURL('**/map**', { timeout: 10000 }),
|
|
wholeYearLink.click()
|
|
]);
|
|
|
|
// Wait for page to settle
|
|
await page.waitForLoadState('networkidle', { timeout: 10000 });
|
|
|
|
// Verify we navigated to the map page
|
|
expect(page.url()).toContain('/map');
|
|
|
|
// The URL parameters might be processed differently (e.g., stripped by Turbo or redirected)
|
|
// Instead of checking URL, verify the panel updates to show the whole year is selected
|
|
// by checking the year in the select dropdown
|
|
const panelVisible = await isPanelVisible(page);
|
|
if (!panelVisible) {
|
|
// Panel might have closed on navigation, reopen it
|
|
await clickCalendarButton(page);
|
|
await page.waitForTimeout(1000);
|
|
}
|
|
|
|
const yearSelect = page.locator('#year-select');
|
|
const selectedYear = await yearSelect.inputValue();
|
|
expect(selectedYear).toBe(expectedYear);
|
|
});
|
|
|
|
test('should update month buttons when year is changed', async ({ page }) => {
|
|
// Open panel
|
|
await clickCalendarButton(page);
|
|
|
|
// Wait for data to load
|
|
await page.waitForTimeout(2000);
|
|
|
|
const yearSelect = page.locator('#year-select');
|
|
|
|
// Get available years
|
|
const options = await yearSelect.locator('option:not([disabled])').all();
|
|
|
|
if (options.length < 2) {
|
|
console.log('Test skipped: Less than 2 years available');
|
|
test.skip();
|
|
return;
|
|
}
|
|
|
|
// Select first year and capture month states
|
|
const firstYearOption = options[0];
|
|
const firstYear = await firstYearOption.getAttribute('value');
|
|
await yearSelect.selectOption(firstYear);
|
|
await page.waitForTimeout(500);
|
|
|
|
// Get enabled months for first year
|
|
const firstYearMonths = await page.locator('#months-grid a:not(.disabled)').count();
|
|
|
|
// Select second year
|
|
const secondYearOption = options[1];
|
|
const secondYear = await secondYearOption.getAttribute('value');
|
|
await yearSelect.selectOption(secondYear);
|
|
await page.waitForTimeout(500);
|
|
|
|
// Get enabled months for second year
|
|
const secondYearMonths = await page.locator('#months-grid a:not(.disabled)').count();
|
|
|
|
// Months should be different (unless both years have same tracked months)
|
|
// At minimum, verify that month buttons are updated (content changed from loading dots)
|
|
const monthButtons = await page.locator('#months-grid a').all();
|
|
|
|
for (const button of monthButtons) {
|
|
const buttonText = await button.textContent();
|
|
// Should not contain loading dots anymore
|
|
expect(buttonText).not.toContain('loading');
|
|
}
|
|
});
|
|
|
|
test('should highlight active month based on current URL parameters', async ({ page }) => {
|
|
// Navigate to a specific month first
|
|
await page.goto('/map?start_at=2024-10-01T00:00&end_at=2024-10-31T23:59');
|
|
await closeOnboardingModal(page);
|
|
await page.waitForSelector('.leaflet-container', { state: 'visible', timeout: 10000 });
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Open calendar panel
|
|
await clickCalendarButton(page);
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Find October button (month index 9, displayed as "Oct")
|
|
const octoberButton = page.locator('#months-grid a[data-month-name="Oct"]');
|
|
await expect(octoberButton).toBeVisible();
|
|
|
|
// Verify October is marked as active
|
|
const hasActiveClass = await octoberButton.evaluate(el =>
|
|
el.classList.contains('btn-active')
|
|
);
|
|
expect(hasActiveClass).toBe(true);
|
|
});
|
|
|
|
test('should show visited cities section in panel', async ({ page }) => {
|
|
// Open panel
|
|
await clickCalendarButton(page);
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Verify visited cities section is present
|
|
const visitedCitiesContainer = page.locator('#visited-cities-container');
|
|
await expect(visitedCitiesContainer).toBeVisible();
|
|
|
|
const visitedCitiesTitle = visitedCitiesContainer.locator('h3');
|
|
await expect(visitedCitiesTitle).toHaveText('Visited cities');
|
|
|
|
const visitedCitiesList = page.locator('#visited-cities-list');
|
|
await expect(visitedCitiesList).toBeVisible();
|
|
|
|
// List should eventually load (either with cities or "No places visited")
|
|
await page.waitForTimeout(2000);
|
|
const listContent = await visitedCitiesList.textContent();
|
|
expect(listContent.length).toBeGreaterThan(0);
|
|
});
|
|
});
|