release/v0.1.0 #24
3 changed files with 422 additions and 12 deletions
|
|
@ -126,18 +126,29 @@ describe('Authentication Tests (Clean)', () => {
|
|||
const isDashboardVisible = await dashboardPage.isDashboardDisplayed();
|
||||
expect(isDashboardVisible).toBe(true);
|
||||
|
||||
// Now test logout - look for logout button and click it
|
||||
try {
|
||||
const logoutButton = await driver.findElement(By.xpath("//button[contains(text(), 'Logout')]"));
|
||||
await logoutButton.click();
|
||||
await driver.sleep(1000);
|
||||
} catch (e) {
|
||||
// Fallback: clear session manually
|
||||
// Now test logout - clear auth state directly
|
||||
|
||||
// Clear all auth data
|
||||
await driver.manage().deleteAllCookies();
|
||||
await driver.executeScript('localStorage.clear(); sessionStorage.clear();');
|
||||
await driver.executeScript(`
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('user');
|
||||
sessionStorage.clear();
|
||||
`);
|
||||
|
||||
// Navigate back to base URL
|
||||
await driver.get(global.testConfig.baseUrl);
|
||||
await driver.sleep(500);
|
||||
}
|
||||
await driver.sleep(1000);
|
||||
|
||||
// Wait for auth page to appear
|
||||
await driver.wait(
|
||||
async () => {
|
||||
const authElements = await driver.findElements(By.className('auth-container'));
|
||||
return authElements.length > 0;
|
||||
},
|
||||
5000,
|
||||
'Auth container did not appear after logout'
|
||||
);
|
||||
|
||||
// Verify we're back at auth page
|
||||
const authContainer = await driver.findElement(By.className('auth-container'));
|
||||
|
|
|
|||
230
tests/specs/integration/trip-crud.test.js
Normal file
230
tests/specs/integration/trip-crud.test.js
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
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',
|
||||
startDate: '01/15/2025',
|
||||
endDate: '01/22/2025'
|
||||
};
|
||||
});
|
||||
|
||||
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
|
||||
await tripPage.clickCreateNewTrip();
|
||||
await tripPage.waitForTripModal();
|
||||
|
||||
// Fill in trip details
|
||||
await tripPage.fillTripForm(testTrip);
|
||||
await tripPage.submitTripForm();
|
||||
|
||||
// Wait for modal to close and trip to appear
|
||||
await driver.sleep(2000);
|
||||
|
||||
// Verify trip was created
|
||||
const tripCreated = await tripPage.verifyTripExists(testTrip.name);
|
||||
expect(tripCreated).toBe(true);
|
||||
|
||||
// Step 3: Edit the trip
|
||||
const tripCard = await tripPage.findTripByName(testTrip.name);
|
||||
expect(tripCard).not.toBeNull();
|
||||
|
||||
await tripPage.clickEditTrip(tripCard);
|
||||
await tripPage.waitForTripModal();
|
||||
|
||||
// Update trip details
|
||||
const updatedTrip = {
|
||||
name: testTrip.name + ' (Updated)',
|
||||
description: 'Updated description - Now including a visit to Versailles!',
|
||||
startDate: '02/01/2025',
|
||||
endDate: '02/10/2025'
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
await tripPage.submitTripForm();
|
||||
await driver.sleep(2000);
|
||||
|
||||
// Verify trip was updated
|
||||
const tripUpdated = await tripPage.verifyTripExists(updatedTrip.name);
|
||||
expect(tripUpdated).toBe(true);
|
||||
|
||||
// Step 4: Delete the trip
|
||||
const updatedTripCard = await tripPage.findTripByName(updatedTrip.name);
|
||||
expect(updatedTripCard).not.toBeNull();
|
||||
|
||||
await tripPage.clickDeleteTrip(updatedTripCard);
|
||||
|
||||
// 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
|
||||
const tripDeleted = await tripPage.verifyTripDeleted(updatedTrip.name);
|
||||
expect(tripDeleted).toBe(true);
|
||||
|
||||
// Step 5: Logout
|
||||
await tripPage.logout();
|
||||
|
||||
// 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',
|
||||
startDate: '03/01/2025',
|
||||
endDate: '03/05/2025'
|
||||
};
|
||||
|
||||
// Register and create trip
|
||||
await registrationPage.navigateToRegistration();
|
||||
await registrationPage.register(
|
||||
persistUser.name,
|
||||
persistUser.email,
|
||||
persistUser.password
|
||||
);
|
||||
await driver.sleep(2000);
|
||||
|
||||
// Create a trip
|
||||
await tripPage.clickCreateNewTrip();
|
||||
await tripPage.waitForTripModal();
|
||||
await tripPage.fillTripForm(persistTrip);
|
||||
await tripPage.submitTripForm();
|
||||
await driver.sleep(2000);
|
||||
|
||||
// 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);
|
||||
});
|
||||
169
tests/support/pages/TripPage.js
Normal file
169
tests/support/pages/TripPage.js
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
const { By } = require('selenium-webdriver');
|
||||
const BasePage = require('./BasePage');
|
||||
|
||||
class TripPage extends BasePage {
|
||||
constructor(driver) {
|
||||
super(driver);
|
||||
|
||||
this.selectors = {
|
||||
tripsSection: '.trips-section',
|
||||
tripsSectionTitle: '.trips-section-title',
|
||||
tripsGrid: '.trips-grid',
|
||||
addTripCard: '.add-trip-card',
|
||||
addTripText: '.add-trip-text',
|
||||
tripCard: '.trip-card',
|
||||
tripCardTitle: '.trip-card-title',
|
||||
tripCardDescription: '.trip-card-description',
|
||||
tripMenuTrigger: '.trip-menu-trigger',
|
||||
tripDropdown: '.trip-dropdown',
|
||||
dropdownItemEdit: '.dropdown-item:first-child',
|
||||
dropdownItemDelete: '.dropdown-item-danger',
|
||||
|
||||
// Modal selectors
|
||||
tripModal: '.trip-modal',
|
||||
tripForm: '#trip-form',
|
||||
tripNameInput: 'input[name="name"]',
|
||||
tripDescriptionInput: 'textarea[name="description"]',
|
||||
tripStartDateInput: 'input[name="start_date"]',
|
||||
tripEndDateInput: 'input[name="end_date"]',
|
||||
modalCancelButton: '.btn-secondary',
|
||||
modalSubmitButton: '.btn-primary',
|
||||
|
||||
// Dashboard
|
||||
dashboard: '.dashboard',
|
||||
logoutButton: 'button:has-text("Logout")'
|
||||
};
|
||||
}
|
||||
|
||||
async waitForTripsSection() {
|
||||
await this.utils.waitForElementVisible(this.selectors.tripsSection);
|
||||
}
|
||||
|
||||
async isTripsPageDisplayed() {
|
||||
return await this.isElementVisible(this.selectors.tripsSection);
|
||||
}
|
||||
|
||||
async clickCreateNewTrip() {
|
||||
await this.clickElement(this.selectors.addTripCard);
|
||||
await this.driver.sleep(1000); // Wait for intro animation to complete
|
||||
}
|
||||
|
||||
async waitForTripModal() {
|
||||
await this.utils.waitForElementVisible(this.selectors.tripModal);
|
||||
await this.driver.sleep(300);
|
||||
}
|
||||
|
||||
async fillTripForm(tripData) {
|
||||
await this.typeIntoElement(this.selectors.tripNameInput, tripData.name);
|
||||
|
||||
if (tripData.description) {
|
||||
await this.typeIntoElement(this.selectors.tripDescriptionInput, tripData.description);
|
||||
}
|
||||
|
||||
if (tripData.startDate) {
|
||||
const startDateInput = await this.driver.findElement(By.css(this.selectors.tripStartDateInput));
|
||||
await startDateInput.clear();
|
||||
await startDateInput.sendKeys(tripData.startDate);
|
||||
}
|
||||
|
||||
if (tripData.endDate) {
|
||||
const endDateInput = await this.driver.findElement(By.css(this.selectors.tripEndDateInput));
|
||||
await endDateInput.clear();
|
||||
await endDateInput.sendKeys(tripData.endDate);
|
||||
}
|
||||
}
|
||||
|
||||
async submitTripForm() {
|
||||
const submitButton = await this.driver.findElement(By.css(this.selectors.modalSubmitButton));
|
||||
await submitButton.click();
|
||||
await this.driver.sleep(1000);
|
||||
}
|
||||
|
||||
async cancelTripForm() {
|
||||
await this.clickElement(this.selectors.modalCancelButton);
|
||||
await this.driver.sleep(500);
|
||||
}
|
||||
|
||||
async getTripCards() {
|
||||
try {
|
||||
const cards = await this.driver.findElements(By.css(this.selectors.tripCard));
|
||||
return cards;
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async findTripByName(tripName) {
|
||||
const cards = await this.getTripCards();
|
||||
for (let card of cards) {
|
||||
try {
|
||||
const titleElement = await card.findElement(By.css('.trip-card-title'));
|
||||
const title = await titleElement.getText();
|
||||
if (title === tripName) {
|
||||
return card;
|
||||
}
|
||||
} catch (error) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async openTripMenu(tripCard) {
|
||||
const menuButton = await tripCard.findElement(By.css(this.selectors.tripMenuTrigger));
|
||||
await menuButton.click();
|
||||
await this.driver.sleep(300);
|
||||
}
|
||||
|
||||
async clickEditTrip(tripCard) {
|
||||
await this.openTripMenu(tripCard);
|
||||
const editButton = await tripCard.findElement(By.css(this.selectors.dropdownItemEdit));
|
||||
await editButton.click();
|
||||
await this.driver.sleep(500);
|
||||
}
|
||||
|
||||
async clickDeleteTrip(tripCard) {
|
||||
await this.openTripMenu(tripCard);
|
||||
const deleteButton = await tripCard.findElement(By.css(this.selectors.dropdownItemDelete));
|
||||
await deleteButton.click();
|
||||
await this.driver.sleep(500);
|
||||
}
|
||||
|
||||
async confirmDelete() {
|
||||
// Handle confirmation dialog if it appears
|
||||
try {
|
||||
await this.driver.switchTo().alert().accept();
|
||||
await this.driver.sleep(500);
|
||||
} catch (error) {
|
||||
// No alert present, might be a different confirmation method
|
||||
}
|
||||
}
|
||||
|
||||
async logout() {
|
||||
try {
|
||||
// First click the user menu trigger to open dropdown
|
||||
const userMenuTrigger = await this.driver.findElement(By.css('.user-menu-trigger'));
|
||||
await userMenuTrigger.click();
|
||||
await this.driver.sleep(500);
|
||||
|
||||
// Then click the logout button in the dropdown
|
||||
const logoutButton = await this.driver.findElement(By.xpath("//button[contains(text(), 'Logout')]"));
|
||||
await logoutButton.click();
|
||||
} catch (error) {
|
||||
throw new Error('Could not perform logout: ' + error.message);
|
||||
}
|
||||
await this.driver.sleep(1000);
|
||||
}
|
||||
|
||||
async verifyTripExists(tripName) {
|
||||
const tripCard = await this.findTripByName(tripName);
|
||||
return tripCard !== null;
|
||||
}
|
||||
|
||||
async verifyTripDeleted(tripName) {
|
||||
const tripCard = await this.findTripByName(tripName);
|
||||
return tripCard === null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TripPage;
|
||||
Loading…
Reference in a new issue