trip-planner/tests/specs/integration/trip-crud.test.js

270 lines
9.4 KiB
JavaScript
Raw Normal View History

2025-09-27 10:56:04 +02:00
const { By, until } = require('selenium-webdriver');
const RegistrationPage = require('../../support/pages/RegistrationPage');
const LoginPage = require('../../support/pages/LoginPage');
const DashboardPage = require('../../support/pages/DashboardPage');
const TripPage = require('../../support/pages/TripPage');
describe('Trip CRUD Operations Test', () => {
let driver;
let registrationPage;
let loginPage;
let dashboardPage;
let tripPage;
let testUser;
let testTrip;
beforeAll(async () => {
driver = await global.createDriver();
registrationPage = new RegistrationPage(driver);
loginPage = new LoginPage(driver);
dashboardPage = new DashboardPage(driver);
tripPage = new TripPage(driver);
// Create unique test data
const timestamp = Date.now();
testUser = {
name: `Trip Test User ${timestamp}`,
email: `trip.test.${timestamp}@example.com`,
password: 'TripTest123!'
};
testTrip = {
name: `Test Trip to Paris ${timestamp}`,
description: 'A wonderful trip to explore the City of Light',
2025-09-30 08:29:17 +02:00
startDate: '2025-01-15',
endDate: '2025-01-22'
2025-09-27 10:56:04 +02:00
};
});
afterAll(async () => {
await global.quitDriver(driver);
});
beforeEach(async () => {
// Clear storage and cookies
await Promise.all([
driver.manage().deleteAllCookies().catch(() => {}),
driver.executeScript('try { localStorage.clear(); sessionStorage.clear(); } catch(e) {}')
]);
// Navigate to base URL
await driver.get(global.testConfig.baseUrl);
await driver.sleep(500);
});
test('Complete trip CRUD flow: login, create, edit, delete, logout', async () => {
// Step 1: Register a new user
await registrationPage.navigateToRegistration();
await registrationPage.register(
testUser.name,
testUser.email,
testUser.password
);
await driver.sleep(2000);
// Verify registration and auto-login to dashboard
const isDashboardVisible = await dashboardPage.isDashboardDisplayed();
expect(isDashboardVisible).toBe(true);
// Wait for trips section to load and animations to complete
await driver.sleep(2000);
const isTripsVisible = await tripPage.isTripsPageDisplayed();
expect(isTripsVisible).toBe(true);
// Step 2: Create a new trip
2025-09-30 08:29:17 +02:00
const addTripCard = await driver.findElement(By.css('.add-trip-card'));
await addTripCard.click();
await driver.wait(until.elementLocated(By.css('.trip-modal')), 10000);
2025-09-27 10:56:04 +02:00
2025-09-30 08:29:17 +02:00
// Use TripPage helper to fill and submit form
2025-09-27 10:56:04 +02:00
await tripPage.fillTripForm(testTrip);
2025-09-30 08:29:17 +02:00
await driver.sleep(1000); // Wait for validation
// Submit with JavaScript click for reliability
const submitButton = await driver.findElement(By.css('.btn-primary'));
await driver.executeScript("arguments[0].scrollIntoView(true);", submitButton);
await driver.sleep(300);
await driver.executeScript("arguments[0].click();", submitButton);
2025-09-27 10:56:04 +02:00
// Wait for modal to close and trip to appear
await driver.sleep(2000);
2025-09-30 08:29:17 +02:00
await driver.wait(async () => {
const modals = await driver.findElements(By.css('.trip-modal'));
for (const modal of modals) {
try {
if (await modal.isDisplayed()) {
return false;
}
} catch (e) {
// Stale element, continue
}
}
return true;
}, 10000);
// Wait for trip card to appear
await driver.sleep(1000);
await driver.wait(until.elementLocated(By.xpath(`//h3[contains(text(), "${testTrip.name}")]`)), 15000);
2025-09-27 10:56:04 +02:00
// Verify trip was created
2025-09-30 08:29:17 +02:00
const tripElements = await driver.findElements(By.xpath(`//h3[contains(text(), "${testTrip.name}")]`));
expect(tripElements.length).toBeGreaterThan(0);
2025-09-27 10:56:04 +02:00
// Step 3: Edit the trip
2025-09-30 08:29:17 +02:00
const tripCard = await driver.findElement(By.xpath(`//h3[contains(text(), "${testTrip.name}")]/ancestor::div[contains(@class, "trip-card")]`));
2025-09-27 10:56:04 +02:00
expect(tripCard).not.toBeNull();
2025-09-30 08:29:17 +02:00
// Click edit button - look for edit icon/button in the trip card
const editButton = await tripCard.findElement(By.css('.edit-btn, .btn-edit, [title="Edit"]'));
await editButton.click();
await driver.wait(until.elementLocated(By.css('.trip-modal')), 10000);
2025-09-27 10:56:04 +02:00
// Update trip details
const updatedTrip = {
name: testTrip.name + ' (Updated)',
description: 'Updated description - Now including a visit to Versailles!',
2025-09-30 08:29:17 +02:00
startDate: '2025-02-01',
endDate: '2025-02-10'
2025-09-27 10:56:04 +02:00
};
// Clear and update fields
const nameInput = await driver.findElement(By.css('input[name="name"]'));
await nameInput.clear();
await nameInput.sendKeys(updatedTrip.name);
const descInput = await driver.findElement(By.css('textarea[name="description"]'));
await descInput.clear();
await descInput.sendKeys(updatedTrip.description);
2025-09-30 08:29:17 +02:00
// Submit the form
const updateButton = await driver.findElement(By.xpath('//button[contains(text(), "Update") or contains(text(), "Save")]'));
await updateButton.click();
2025-09-27 10:56:04 +02:00
await driver.sleep(2000);
// Verify trip was updated
2025-09-30 08:29:17 +02:00
const updatedTripElements = await driver.findElements(By.xpath(`//h3[contains(text(), "${updatedTrip.name}")]`));
expect(updatedTripElements.length).toBeGreaterThan(0);
2025-09-27 10:56:04 +02:00
// Step 4: Delete the trip
2025-09-30 08:29:17 +02:00
const updatedTripCard = await driver.findElement(By.xpath(`//h3[contains(text(), "${updatedTrip.name}")]/ancestor::div[contains(@class, "trip-card")]`));
2025-09-27 10:56:04 +02:00
expect(updatedTripCard).not.toBeNull();
2025-09-30 08:29:17 +02:00
// Click delete button - look for delete icon/button in the trip card
const deleteButton = await updatedTripCard.findElement(By.css('.delete-btn, .btn-delete, [title="Delete"]'));
await deleteButton.click();
2025-09-27 10:56:04 +02:00
// Handle any confirmation dialog
await driver.sleep(500);
// Check if there's a confirmation modal or alert
try {
// Try to handle browser alert
const alert = await driver.switchTo().alert();
await alert.accept();
} catch (e) {
// If no alert, might be a custom confirmation modal
try {
// Look for confirmation button in modal
const confirmButton = await driver.findElement(By.xpath("//button[contains(text(), 'Delete') or contains(text(), 'Confirm')]"));
await confirmButton.click();
} catch (e2) {
// No confirmation needed
}
}
await driver.sleep(2000);
// Verify trip was deleted
2025-09-30 08:29:17 +02:00
const remainingTripElements = await driver.findElements(By.xpath(`//h3[contains(text(), "${updatedTrip.name}")]`));
expect(remainingTripElements.length).toBe(0);
2025-09-27 10:56:04 +02:00
// Step 5: Logout
2025-09-30 08:29:17 +02:00
// First click the user dropdown trigger
const userMenuTrigger = await driver.findElement(By.className('user-menu-trigger'));
await userMenuTrigger.click();
await driver.sleep(500);
// Then click the logout button in the dropdown
const logoutButton = await driver.findElement(By.xpath("//button[contains(text(), 'Logout')]"));
await logoutButton.click();
2025-09-27 10:56:04 +02:00
// Wait for redirect to auth page
await driver.wait(
async () => {
try {
const elements = await driver.findElements(By.className('auth-container'));
return elements.length > 0;
} catch (e) {
return false;
}
},
5000,
'Auth container did not appear after logout'
);
// Verify logout - should see auth container
const authContainer = await driver.findElement(By.className('auth-container'));
const isAuthVisible = await authContainer.isDisplayed();
expect(isAuthVisible).toBe(true);
// Additional verification: Ensure user is really logged out
const dashboardElements = await driver.findElements(By.className('dashboard'));
expect(dashboardElements.length).toBe(0);
}, 120000); // 2 minutes timeout for the complete flow
test('Login with existing user and verify trips persist', async () => {
// This test verifies that we can login and see trips
// First create a user and a trip
const timestamp = Date.now();
const persistUser = {
name: `Persist Test ${timestamp}`,
email: `persist.${timestamp}@example.com`,
password: 'Persist123!'
};
const persistTrip = {
name: `Persistent Trip ${timestamp}`,
description: 'This trip should persist after logout',
2025-09-30 08:29:17 +02:00
startDate: '2025-03-01',
endDate: '2025-03-05'
2025-09-27 10:56:04 +02:00
};
// Register and create trip
await registrationPage.navigateToRegistration();
await registrationPage.register(
persistUser.name,
persistUser.email,
persistUser.password
);
await driver.sleep(2000);
// Create a trip
2025-09-30 08:29:17 +02:00
const addTripCard = await driver.findElement(By.css('.add-trip-card'));
await addTripCard.click();
await driver.wait(until.elementLocated(By.css('.trip-modal')), 10000);
2025-09-27 10:56:04 +02:00
await tripPage.fillTripForm(persistTrip);
await tripPage.submitTripForm();
2025-09-30 08:29:17 +02:00
// Wait for trip to appear
await driver.wait(until.elementLocated(By.xpath(`//h3[contains(text(), "${persistTrip.name}")]`)), 10000);
2025-09-27 10:56:04 +02:00
// Logout
await tripPage.logout();
await driver.sleep(1000);
// Login again
await loginPage.navigateToLogin();
await loginPage.login(persistUser.email, persistUser.password);
await driver.sleep(2000);
// Verify dashboard is visible
const isDashboardVisible = await dashboardPage.isDashboardDisplayed();
expect(isDashboardVisible).toBe(true);
// Verify trip still exists
await driver.sleep(1000);
const tripExists = await tripPage.verifyTripExists(persistTrip.name);
expect(tripExists).toBe(true);
}, 90000);
});