Implement graceful shutdown handling in CLI; add cleanup logic to TestRunner and Executor for improved resource management during termination. Update sleep durations in step1.test for consistency.
This commit is contained in:
60
src/cli.js
60
src/cli.js
@@ -79,7 +79,46 @@ class TestRunner {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async cleanup() {
|
||||||
|
if (this.executor) {
|
||||||
|
await this.executor.cleanup();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global reference to runner for cleanup
|
||||||
|
let currentRunner = null;
|
||||||
|
|
||||||
|
// Signal handler for clean shutdown
|
||||||
|
async function handleShutdown(signal) {
|
||||||
|
console.log(`\n🛑 Received ${signal}, shutting down gracefully...`);
|
||||||
|
|
||||||
|
if (currentRunner) {
|
||||||
|
// Signal the executor to stop
|
||||||
|
if (currentRunner.executor) {
|
||||||
|
currentRunner.executor.shouldStop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await currentRunner.cleanup();
|
||||||
|
console.log('✅ Browser cleanup completed');
|
||||||
|
} catch (error) {
|
||||||
|
console.log('⚠️ Browser cleanup had issues:', error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('👋 Goodbye!');
|
||||||
|
|
||||||
|
// Give a moment for any remaining cleanup, then exit
|
||||||
|
setTimeout(() => {
|
||||||
|
process.exit(0);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register signal handlers
|
||||||
|
process.on('SIGINT', handleShutdown); // Ctrl+C
|
||||||
|
process.on('SIGTERM', handleShutdown); // Termination signal
|
||||||
|
|
||||||
// CLI handling
|
// CLI handling
|
||||||
async function main() {
|
async function main() {
|
||||||
@@ -118,13 +157,32 @@ async function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const runner = new TestRunner({ headless, disableAnimations, fullPageScreenshots, lint, strict });
|
const runner = new TestRunner({ headless, disableAnimations, fullPageScreenshots, lint, strict });
|
||||||
|
currentRunner = runner; // Store reference for cleanup
|
||||||
|
|
||||||
|
try {
|
||||||
await runner.runTestFile(testFile, profile);
|
await runner.runTestFile(testFile, profile);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Test execution failed:', error.message);
|
||||||
|
|
||||||
|
// Clean up on error
|
||||||
|
try {
|
||||||
|
await runner.cleanup();
|
||||||
|
} catch (cleanupError) {
|
||||||
|
// Ignore cleanup errors
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
|
} finally {
|
||||||
|
currentRunner = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run if called directly
|
// Run if called directly
|
||||||
if (require.main === module) {
|
if (require.main === module) {
|
||||||
main().catch(console.error);
|
main().catch((error) => {
|
||||||
|
console.error('❌ Unexpected error:', error.message);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TestRunner;
|
module.exports = TestRunner;
|
||||||
112
src/executor.js
112
src/executor.js
@@ -16,6 +16,7 @@ class TestExecutor {
|
|||||||
this.fullPageScreenshots = options.fullPageScreenshots || false; // Default to viewport screenshots
|
this.fullPageScreenshots = options.fullPageScreenshots || false; // Default to viewport screenshots
|
||||||
this.enableScreenshots = options.enableScreenshots !== false; // Default to enable screenshots
|
this.enableScreenshots = options.enableScreenshots !== false; // Default to enable screenshots
|
||||||
this.variables = {}; // Store extracted variables
|
this.variables = {}; // Store extracted variables
|
||||||
|
this.shouldStop = false; // Flag to stop execution on shutdown
|
||||||
|
|
||||||
this.profiles = {
|
this.profiles = {
|
||||||
Chrome: {
|
Chrome: {
|
||||||
@@ -44,6 +45,12 @@ class TestExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < commands.length; i++) {
|
for (let i = 0; i < commands.length; i++) {
|
||||||
|
// Check if we should stop execution (e.g., due to Ctrl+C)
|
||||||
|
if (this.shouldStop) {
|
||||||
|
console.log('🛑 Stopping test execution due to shutdown request');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const command = commands[i];
|
const command = commands[i];
|
||||||
|
|
||||||
// Check for pause before executing command (only for interactive commands)
|
// Check for pause before executing command (only for interactive commands)
|
||||||
@@ -58,7 +65,16 @@ class TestExecutor {
|
|||||||
|
|
||||||
// Update status before executing command
|
// Update status before executing command
|
||||||
if (!this.headless) {
|
if (!this.headless) {
|
||||||
await this.updateStatus(command, false);
|
// Find next interactive command for display when paused
|
||||||
|
let nextInteractiveCommand = null;
|
||||||
|
for (let j = i; j < commands.length; j++) {
|
||||||
|
if (this.isInteractiveCommand(commands[j])) {
|
||||||
|
nextInteractiveCommand = commands[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.updateStatus(command, false, nextInteractiveCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for manual dump requests
|
// Check for manual dump requests
|
||||||
@@ -66,6 +82,12 @@ class TestExecutor {
|
|||||||
await this.checkDumpRequests();
|
await this.checkDumpRequests();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check again if we should stop before executing the command
|
||||||
|
if (this.shouldStop) {
|
||||||
|
console.log('🛑 Stopping test execution due to shutdown request');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const jumpCount = await this.executeCommand(command);
|
const jumpCount = await this.executeCommand(command);
|
||||||
|
|
||||||
// Handle jump commands
|
// Handle jump commands
|
||||||
@@ -76,7 +98,16 @@ class TestExecutor {
|
|||||||
|
|
||||||
// Update status after completing command
|
// Update status after completing command
|
||||||
if (!this.headless) {
|
if (!this.headless) {
|
||||||
await this.updateStatus(command, true);
|
// Find next interactive command for display when paused
|
||||||
|
let nextInteractiveCommand = null;
|
||||||
|
for (let j = i + 1; j < commands.length; j++) {
|
||||||
|
if (this.isInteractiveCommand(commands[j])) {
|
||||||
|
nextInteractiveCommand = commands[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.updateStatus(command, true, nextInteractiveCommand);
|
||||||
|
|
||||||
// If this was a step request, pause again after this interactive command
|
// If this was a step request, pause again after this interactive command
|
||||||
if (this.shouldPauseAfterStep && this.isInteractiveCommand(command)) {
|
if (this.shouldPauseAfterStep && this.isInteractiveCommand(command)) {
|
||||||
@@ -204,6 +235,12 @@ class TestExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async executeCommand(command) {
|
async executeCommand(command) {
|
||||||
|
// Check if we should stop before executing any command
|
||||||
|
if (this.shouldStop) {
|
||||||
|
console.log('🛑 Skipping command execution due to shutdown request');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a clean one-line representation of the command
|
// Create a clean one-line representation of the command
|
||||||
const commandStr = this.formatCommandForOutput(command);
|
const commandStr = this.formatCommandForOutput(command);
|
||||||
console.log(`Executing: ${commandStr}`);
|
console.log(`Executing: ${commandStr}`);
|
||||||
@@ -1003,6 +1040,7 @@ class TestExecutor {
|
|||||||
const button = this;
|
const button = this;
|
||||||
const stepBtn = document.getElementById('step-btn');
|
const stepBtn = document.getElementById('step-btn');
|
||||||
const indicator = document.getElementById('status-indicator');
|
const indicator = document.getElementById('status-indicator');
|
||||||
|
const titleEl = document.querySelector('.status-section .status-title');
|
||||||
|
|
||||||
if (isPaused) {
|
if (isPaused) {
|
||||||
button.textContent = '▶️ Resume';
|
button.textContent = '▶️ Resume';
|
||||||
@@ -1010,6 +1048,11 @@ class TestExecutor {
|
|||||||
indicator.className = 'status-indicator status-paused';
|
indicator.className = 'status-indicator status-paused';
|
||||||
stepBtn.disabled = false;
|
stepBtn.disabled = false;
|
||||||
|
|
||||||
|
// Update title to show next command
|
||||||
|
if (titleEl) {
|
||||||
|
titleEl.innerHTML = '<span id="status-indicator" class="status-indicator status-paused"></span>Next Command (+1 Step)';
|
||||||
|
}
|
||||||
|
|
||||||
// Store pause state in window to communicate with executor
|
// Store pause state in window to communicate with executor
|
||||||
window.playwrongPaused = true;
|
window.playwrongPaused = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -1018,6 +1061,11 @@ class TestExecutor {
|
|||||||
indicator.className = 'status-indicator status-running';
|
indicator.className = 'status-indicator status-running';
|
||||||
stepBtn.disabled = true;
|
stepBtn.disabled = true;
|
||||||
|
|
||||||
|
// Update title to show current command
|
||||||
|
if (titleEl) {
|
||||||
|
titleEl.innerHTML = '<span id="status-indicator" class="status-indicator status-running"></span>Current Command';
|
||||||
|
}
|
||||||
|
|
||||||
// Resume execution
|
// Resume execution
|
||||||
window.playwrongPaused = false;
|
window.playwrongPaused = false;
|
||||||
}
|
}
|
||||||
@@ -1106,6 +1154,12 @@ class TestExecutor {
|
|||||||
|
|
||||||
// Wait until user resumes, but also check for dump requests and step requests while paused
|
// Wait until user resumes, but also check for dump requests and step requests while paused
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// Check if we should stop execution (e.g., due to Ctrl+C)
|
||||||
|
if (this.shouldStop) {
|
||||||
|
console.log('🛑 Breaking out of pause due to shutdown request');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
await this.page.waitForTimeout(500); // Check every 500ms
|
await this.page.waitForTimeout(500); // Check every 500ms
|
||||||
|
|
||||||
// Check for dump requests even while paused
|
// Check for dump requests even while paused
|
||||||
@@ -1201,7 +1255,7 @@ class TestExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateStatus(command, isCompleted = false) {
|
async updateStatus(command, isCompleted = false, nextInteractiveCommand = null) {
|
||||||
if (!this.statusPage || this.headless) return;
|
if (!this.statusPage || this.headless) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1220,10 +1274,27 @@ class TestExecutor {
|
|||||||
|
|
||||||
const progress = this.totalCommands > 0 ? (this.completedCommands / this.totalCommands) * 100 : 0;
|
const progress = this.totalCommands > 0 ? (this.completedCommands / this.totalCommands) * 100 : 0;
|
||||||
|
|
||||||
await this.statusPage.evaluate(({ command, completed, total, elapsed, progress }) => {
|
await this.statusPage.evaluate(({ command, nextInteractiveCommand, completed, total, elapsed, progress }) => {
|
||||||
// Update current command
|
// Update command display based on pause state
|
||||||
const commandEl = document.getElementById('current-command');
|
const commandEl = document.getElementById('current-command');
|
||||||
|
const indicator = document.getElementById('status-indicator');
|
||||||
|
const titleEl = document.querySelector('.status-section .status-title');
|
||||||
|
|
||||||
|
if (window.playwrongPaused && nextInteractiveCommand) {
|
||||||
|
// When paused, show next interactive command
|
||||||
|
if (commandEl) commandEl.textContent = nextInteractiveCommand;
|
||||||
|
if (indicator) indicator.className = 'status-indicator status-paused';
|
||||||
|
if (titleEl) {
|
||||||
|
titleEl.innerHTML = '<span id="status-indicator" class="status-indicator status-paused"></span>Next Command (+1 Step)';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// When running, show current command
|
||||||
if (commandEl) commandEl.textContent = command;
|
if (commandEl) commandEl.textContent = command;
|
||||||
|
if (indicator) indicator.className = 'status-indicator status-running';
|
||||||
|
if (titleEl) {
|
||||||
|
titleEl.innerHTML = '<span id="status-indicator" class="status-indicator status-running"></span>Current Command';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update statistics
|
// Update statistics
|
||||||
const completedEl = document.getElementById('completed-count');
|
const completedEl = document.getElementById('completed-count');
|
||||||
@@ -1239,14 +1310,9 @@ class TestExecutor {
|
|||||||
const progressEl = document.getElementById('progress-fill');
|
const progressEl = document.getElementById('progress-fill');
|
||||||
if (progressEl) progressEl.style.width = progress + '%';
|
if (progressEl) progressEl.style.width = progress + '%';
|
||||||
|
|
||||||
// Update status indicator (only if not paused)
|
|
||||||
const indicator = document.getElementById('status-indicator');
|
|
||||||
if (indicator && !window.playwrongPaused) {
|
|
||||||
indicator.className = 'status-indicator status-running';
|
|
||||||
}
|
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
command: this.formatCommandForOutput(command),
|
command: this.formatCommandForOutput(command),
|
||||||
|
nextInteractiveCommand: nextInteractiveCommand ? this.formatCommandForOutput(nextInteractiveCommand) : null,
|
||||||
completed: this.completedCommands,
|
completed: this.completedCommands,
|
||||||
total: this.totalCommands,
|
total: this.totalCommands,
|
||||||
elapsed: elapsedSeconds,
|
elapsed: elapsedSeconds,
|
||||||
@@ -1925,9 +1991,27 @@ class TestExecutor {
|
|||||||
// Ignore errors when closing status browser
|
// Ignore errors when closing status browser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.page) await this.page.close();
|
if (this.page) {
|
||||||
if (this.context) await this.context.close();
|
try {
|
||||||
if (this.browser) await this.browser.close();
|
await this.page.close();
|
||||||
|
} catch (error) {
|
||||||
|
// Ignore errors when closing page
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.context) {
|
||||||
|
try {
|
||||||
|
await this.context.close();
|
||||||
|
} catch (error) {
|
||||||
|
// Ignore errors when closing context
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.browser) {
|
||||||
|
try {
|
||||||
|
await this.browser.close();
|
||||||
|
} catch (error) {
|
||||||
|
// Ignore errors when closing browser
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveEnvironmentVariables(value) {
|
resolveEnvironmentVariables(value) {
|
||||||
|
|||||||
@@ -62,12 +62,12 @@ sleep 100 "stadt fill"
|
|||||||
wait element=textarea name="note"
|
wait element=textarea name="note"
|
||||||
scroll element=textarea name="note"
|
scroll element=textarea name="note"
|
||||||
fill element=textarea name="note" value="Musteranmerkung"
|
fill element=textarea name="note" value="Musteranmerkung"
|
||||||
sleep 1000000 "note fill"
|
sleep 100 "note fill"
|
||||||
scroll element=button childText="Bestellung abschließen"
|
scroll element=button childText="Bestellung abschließen"
|
||||||
wait element=label childText="Bestimmungen"
|
wait element=label childText="Bestimmungen"
|
||||||
click element=label childText="Bestimmungen"
|
click element=label childText="Bestimmungen"
|
||||||
sleep 100 "checkbox checked"
|
sleep 100 "checkbox checked"
|
||||||
wait element=button childText="Bestellung abschließen"
|
wait element=button childText="Bestellung abschließen"
|
||||||
click element=button childText="Bestellung abschließen"
|
click element=button childText="Bestellung abschließen"
|
||||||
sleep 300000 "order completion"
|
sleep 3000 "order completion"
|
||||||
|
|
||||||
|
|||||||
77
step1_dhl.test
Normal file
77
step1_dhl.test
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
PlayWrong Test - Complete E-commerce Flow
|
||||||
|
This test demonstrates the full purchase flow from product selection to order completion
|
||||||
|
with beautiful animations and environment variable support
|
||||||
|
Part 1: Load Growheads, put one item in the cart and go to checkout
|
||||||
|
Part 2: Fill in the checkout form
|
||||||
|
Part 3: Login to the email account
|
||||||
|
*/
|
||||||
|
use "Chrome"
|
||||||
|
|
||||||
|
# Part 1 - Load Growheads, put one item in the cart and go to checkout
|
||||||
|
open "https://dev.seedheads.de"
|
||||||
|
sleep 200 "page load"
|
||||||
|
wait element=a href=/Kategorie/Seeds
|
||||||
|
click element=a href=/Kategorie/Seeds
|
||||||
|
sleep 200 "seed click"
|
||||||
|
wait element=button childText="In den Korb"
|
||||||
|
click element=button childText="In den Korb"
|
||||||
|
sleep 200 "in korb click"
|
||||||
|
wait element=span class="MuiBadge-badge" childText="1"
|
||||||
|
click element=button child=span(class="MuiBadge-badge" childText="1")
|
||||||
|
sleep 200 "korb click"
|
||||||
|
wait element=button childText="Weiter zur Kasse"
|
||||||
|
click element=button childText="Weiter zur Kasse"
|
||||||
|
sleep 200 "weiter click"
|
||||||
|
wait element=input type="email"
|
||||||
|
fill element=input type="email" value="autotest@growheads.de"
|
||||||
|
sleep 200 "email fill"
|
||||||
|
wait element=input type="password"
|
||||||
|
fill element=input type="password" value="$PASSWORD"
|
||||||
|
sleep 200 "password fill"
|
||||||
|
wait element=button childText="ANMELDEN" class="MuiButton-fullWidth"
|
||||||
|
click element=button childText="ANMELDEN" class="MuiButton-fullWidth"
|
||||||
|
sleep 2000 "anmelden click"
|
||||||
|
#dump "isServer"
|
||||||
|
jumpIfNot element=span childText="Server-Warenkorb löschen" jump=2
|
||||||
|
click element=button childText="Weiter"
|
||||||
|
sleep 2000 "anmelden click"
|
||||||
|
|
||||||
|
# Part 2 - Fill in the checkout form
|
||||||
|
|
||||||
|
wait element=input name="firstName"
|
||||||
|
scroll element=span childText="Vorname"
|
||||||
|
fill element=input name="firstName" value="Max"
|
||||||
|
sleep 100 "vorname fill"
|
||||||
|
wait element=input name="lastName"
|
||||||
|
fill element=input name="lastName" value="Muster"
|
||||||
|
sleep 100 "nachname fill"
|
||||||
|
wait element=input name="street"
|
||||||
|
fill element=input name="street" value="Muster"
|
||||||
|
sleep 100 "strasse fill"
|
||||||
|
wait element=input name="houseNumber"
|
||||||
|
fill element=input name="houseNumber" value="420"
|
||||||
|
sleep 100 "hausnummer fill"
|
||||||
|
wait element=input name="postalCode"
|
||||||
|
fill element=input name="postalCode" value="42023"
|
||||||
|
sleep 100 "plz fill"
|
||||||
|
wait element=input name="city"
|
||||||
|
fill element=input name="city" value="Muster"
|
||||||
|
sleep 100 "stadt fill"
|
||||||
|
|
||||||
|
wait element=textarea name="note"
|
||||||
|
scroll element=textarea name="note"
|
||||||
|
fill element=textarea name="note" value="Musteranmerkung"
|
||||||
|
sleep 100 "note fill"
|
||||||
|
wait element=input id="DHL" name="deliveryMethod" value="DHL" type="radio"
|
||||||
|
scroll element=input id="DHL" name="deliveryMethod" value="DHL" type="radio"
|
||||||
|
click element=input id="DHL" name="deliveryMethod" value="DHL" type="radio"
|
||||||
|
sleep 100 "dhl click"
|
||||||
|
wait element=label childText="Bestimmungen"
|
||||||
|
scroll element=button childText="Bestellung abschließen"
|
||||||
|
click element=label childText="Bestimmungen"
|
||||||
|
sleep 100 "checkbox checked"
|
||||||
|
wait element=button childText="Bestellung abschließen"
|
||||||
|
click element=button childText="Bestellung abschließen"
|
||||||
|
sleep 3000 "order completion"
|
||||||
|
|
||||||
80
step1_dhl_nach.test
Normal file
80
step1_dhl_nach.test
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
PlayWrong Test - Complete E-commerce Flow
|
||||||
|
This test demonstrates the full purchase flow from product selection to order completion
|
||||||
|
with beautiful animations and environment variable support
|
||||||
|
Part 1: Load Growheads, put one item in the cart and go to checkout
|
||||||
|
Part 2: Fill in the checkout form
|
||||||
|
Part 3: Login to the email account
|
||||||
|
*/
|
||||||
|
use "Chrome"
|
||||||
|
|
||||||
|
# Part 1 - Load Growheads, put one item in the cart and go to checkout
|
||||||
|
open "https://dev.seedheads.de"
|
||||||
|
sleep 200 "page load"
|
||||||
|
wait element=a href=/Kategorie/Seeds
|
||||||
|
click element=a href=/Kategorie/Seeds
|
||||||
|
sleep 200 "seed click"
|
||||||
|
wait element=button childText="In den Korb"
|
||||||
|
click element=button childText="In den Korb"
|
||||||
|
sleep 200 "in korb click"
|
||||||
|
wait element=span class="MuiBadge-badge" childText="1"
|
||||||
|
click element=button child=span(class="MuiBadge-badge" childText="1")
|
||||||
|
sleep 200 "korb click"
|
||||||
|
wait element=button childText="Weiter zur Kasse"
|
||||||
|
click element=button childText="Weiter zur Kasse"
|
||||||
|
sleep 200 "weiter click"
|
||||||
|
wait element=input type="email"
|
||||||
|
fill element=input type="email" value="autotest@growheads.de"
|
||||||
|
sleep 200 "email fill"
|
||||||
|
wait element=input type="password"
|
||||||
|
fill element=input type="password" value="$PASSWORD"
|
||||||
|
sleep 200 "password fill"
|
||||||
|
wait element=button childText="ANMELDEN" class="MuiButton-fullWidth"
|
||||||
|
click element=button childText="ANMELDEN" class="MuiButton-fullWidth"
|
||||||
|
sleep 2000 "anmelden click"
|
||||||
|
#dump "isServer"
|
||||||
|
jumpIfNot element=span childText="Server-Warenkorb löschen" jump=2
|
||||||
|
click element=button childText="Weiter"
|
||||||
|
sleep 2000 "anmelden click"
|
||||||
|
|
||||||
|
# Part 2 - Fill in the checkout form
|
||||||
|
|
||||||
|
wait element=input name="firstName"
|
||||||
|
scroll element=span childText="Vorname"
|
||||||
|
fill element=input name="firstName" value="Max"
|
||||||
|
sleep 100 "vorname fill"
|
||||||
|
wait element=input name="lastName"
|
||||||
|
fill element=input name="lastName" value="Muster"
|
||||||
|
sleep 100 "nachname fill"
|
||||||
|
wait element=input name="street"
|
||||||
|
fill element=input name="street" value="Muster"
|
||||||
|
sleep 100 "strasse fill"
|
||||||
|
wait element=input name="houseNumber"
|
||||||
|
fill element=input name="houseNumber" value="420"
|
||||||
|
sleep 100 "hausnummer fill"
|
||||||
|
wait element=input name="postalCode"
|
||||||
|
fill element=input name="postalCode" value="42023"
|
||||||
|
sleep 100 "plz fill"
|
||||||
|
wait element=input name="city"
|
||||||
|
fill element=input name="city" value="Muster"
|
||||||
|
sleep 100 "stadt fill"
|
||||||
|
|
||||||
|
wait element=textarea name="note"
|
||||||
|
scroll element=textarea name="note"
|
||||||
|
fill element=textarea name="note" value="Musteranmerkung"
|
||||||
|
sleep 100 "note fill"
|
||||||
|
wait element=input id="DHL" name="deliveryMethod" value="DHL" type="radio"
|
||||||
|
scroll element=input id="DHL" name="deliveryMethod" value="DHL" type="radio"
|
||||||
|
click element=input id="DHL" name="deliveryMethod" value="DHL" type="radio"
|
||||||
|
sleep 100 "dhl click"
|
||||||
|
wait element=input id="onDelivery" name="paymentMethod" value="onDelivery" type="radio"
|
||||||
|
scroll element=input id="onDelivery" name="paymentMethod" value="onDelivery" type="radio"
|
||||||
|
click element=input id="onDelivery" name="paymentMethod" value="onDelivery" type="radio"
|
||||||
|
sleep 100 "on delivery click"
|
||||||
|
scroll element=button childText="Bestellung abschließen"
|
||||||
|
click element=label childText="Bestimmungen"
|
||||||
|
sleep 100 "checkbox checked"
|
||||||
|
wait element=button childText="Bestellung abschließen"
|
||||||
|
click element=button childText="Bestellung abschließen"
|
||||||
|
sleep 3000 "order completion"
|
||||||
|
|
||||||
77
step1_dpd.test
Normal file
77
step1_dpd.test
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
PlayWrong Test - Complete E-commerce Flow
|
||||||
|
This test demonstrates the full purchase flow from product selection to order completion
|
||||||
|
with beautiful animations and environment variable support
|
||||||
|
Part 1: Load Growheads, put one item in the cart and go to checkout
|
||||||
|
Part 2: Fill in the checkout form
|
||||||
|
Part 3: Login to the email account
|
||||||
|
*/
|
||||||
|
use "Chrome"
|
||||||
|
|
||||||
|
# Part 1 - Load Growheads, put one item in the cart and go to checkout
|
||||||
|
open "https://dev.seedheads.de"
|
||||||
|
sleep 200 "page load"
|
||||||
|
wait element=a href=/Kategorie/Seeds
|
||||||
|
click element=a href=/Kategorie/Seeds
|
||||||
|
sleep 200 "seed click"
|
||||||
|
wait element=button childText="In den Korb"
|
||||||
|
click element=button childText="In den Korb"
|
||||||
|
sleep 200 "in korb click"
|
||||||
|
wait element=span class="MuiBadge-badge" childText="1"
|
||||||
|
click element=button child=span(class="MuiBadge-badge" childText="1")
|
||||||
|
sleep 200 "korb click"
|
||||||
|
wait element=button childText="Weiter zur Kasse"
|
||||||
|
click element=button childText="Weiter zur Kasse"
|
||||||
|
sleep 200 "weiter click"
|
||||||
|
wait element=input type="email"
|
||||||
|
fill element=input type="email" value="autotest@growheads.de"
|
||||||
|
sleep 200 "email fill"
|
||||||
|
wait element=input type="password"
|
||||||
|
fill element=input type="password" value="$PASSWORD"
|
||||||
|
sleep 200 "password fill"
|
||||||
|
wait element=button childText="ANMELDEN" class="MuiButton-fullWidth"
|
||||||
|
click element=button childText="ANMELDEN" class="MuiButton-fullWidth"
|
||||||
|
sleep 2000 "anmelden click"
|
||||||
|
#dump "isServer"
|
||||||
|
jumpIfNot element=span childText="Server-Warenkorb löschen" jump=2
|
||||||
|
click element=button childText="Weiter"
|
||||||
|
sleep 2000 "anmelden click"
|
||||||
|
|
||||||
|
# Part 2 - Fill in the checkout form
|
||||||
|
|
||||||
|
wait element=input name="firstName"
|
||||||
|
scroll element=span childText="Vorname"
|
||||||
|
fill element=input name="firstName" value="Max"
|
||||||
|
sleep 100 "vorname fill"
|
||||||
|
wait element=input name="lastName"
|
||||||
|
fill element=input name="lastName" value="Muster"
|
||||||
|
sleep 100 "nachname fill"
|
||||||
|
wait element=input name="street"
|
||||||
|
fill element=input name="street" value="Muster"
|
||||||
|
sleep 100 "strasse fill"
|
||||||
|
wait element=input name="houseNumber"
|
||||||
|
fill element=input name="houseNumber" value="420"
|
||||||
|
sleep 100 "hausnummer fill"
|
||||||
|
wait element=input name="postalCode"
|
||||||
|
fill element=input name="postalCode" value="42023"
|
||||||
|
sleep 100 "plz fill"
|
||||||
|
wait element=input name="city"
|
||||||
|
fill element=input name="city" value="Muster"
|
||||||
|
sleep 100 "stadt fill"
|
||||||
|
|
||||||
|
wait element=textarea name="note"
|
||||||
|
scroll element=textarea name="note"
|
||||||
|
fill element=textarea name="note" value="Musteranmerkung"
|
||||||
|
sleep 100 "note fill"
|
||||||
|
wait element=input id="DPD" name="deliveryMethod" value="DPD" type="radio"
|
||||||
|
scroll element=input id="DPD" name="deliveryMethod" value="DPD" type="radio"
|
||||||
|
click element=input id="DPD" name="deliveryMethod" value="DPD" type="radio"
|
||||||
|
sleep 100 "dpd click"
|
||||||
|
wait element=label childText="Bestimmungen"
|
||||||
|
scroll element=button childText="Bestellung abschließen"
|
||||||
|
click element=label childText="Bestimmungen"
|
||||||
|
sleep 100 "checkbox checked"
|
||||||
|
wait element=button childText="Bestellung abschließen"
|
||||||
|
click element=button childText="Bestellung abschließen"
|
||||||
|
sleep 3000 "order completion"
|
||||||
|
|
||||||
Reference in New Issue
Block a user