Refactor test execution and linter to support new 'follow' command for window switching, enhance status tracking with visual indicators, and update extraction syntax for improved clarity
This commit is contained in:
@@ -59,7 +59,7 @@
|
|||||||
"patterns": [
|
"patterns": [
|
||||||
{
|
{
|
||||||
"name": "keyword.control.playwrong",
|
"name": "keyword.control.playwrong",
|
||||||
"match": "\\b(use|open|wait|click|fill|scroll|sleep|dump|break|switch to new window|switch to tab|extract)\\b"
|
"match": "\\b(use|open|wait|click|fill|scroll|sleep|dump|break|follow|switch to tab|extract)\\b"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "entity.name.function.playwrong",
|
"name": "entity.name.function.playwrong",
|
||||||
|
|||||||
281
src/executor.js
281
src/executor.js
@@ -37,8 +37,24 @@ class TestExecutor {
|
|||||||
try {
|
try {
|
||||||
await this.setup(profileName);
|
await this.setup(profileName);
|
||||||
|
|
||||||
|
// Set total commands for status tracking
|
||||||
|
this.totalCommands = commands.length;
|
||||||
|
if (this.statusPage && !this.headless) {
|
||||||
|
await this.updateStatus({ type: 'initializing' }, false);
|
||||||
|
}
|
||||||
|
|
||||||
for (const command of commands) {
|
for (const command of commands) {
|
||||||
|
// Update status before executing command
|
||||||
|
if (!this.headless) {
|
||||||
|
await this.updateStatus(command, false);
|
||||||
|
}
|
||||||
|
|
||||||
await this.executeCommand(command);
|
await this.executeCommand(command);
|
||||||
|
|
||||||
|
// Update status after completing command
|
||||||
|
if (!this.headless) {
|
||||||
|
await this.updateStatus(command, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -81,6 +97,11 @@ class TestExecutor {
|
|||||||
|
|
||||||
this.page = await this.context.newPage();
|
this.page = await this.context.newPage();
|
||||||
|
|
||||||
|
// Create status window for headed mode AFTER main page so it appears on top
|
||||||
|
if (!this.headless) {
|
||||||
|
await this.createStatusWindow();
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure consistent viewport size
|
// Ensure consistent viewport size
|
||||||
await this.page.setViewportSize(profile.viewport);
|
await this.page.setViewportSize(profile.viewport);
|
||||||
|
|
||||||
@@ -206,8 +227,8 @@ class TestExecutor {
|
|||||||
await this.sleep(command);
|
await this.sleep(command);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'switchToNewWindow':
|
case 'follow':
|
||||||
await this.switchToNewWindow();
|
await this.followToNewWindow();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'switchToTab':
|
case 'switchToTab':
|
||||||
@@ -580,6 +601,7 @@ class TestExecutor {
|
|||||||
|
|
||||||
// Add visual sleep animation with countdown in headed mode
|
// Add visual sleep animation with countdown in headed mode
|
||||||
if (!this.headless) {
|
if (!this.headless) {
|
||||||
|
try {
|
||||||
await this.page.addStyleTag({
|
await this.page.addStyleTag({
|
||||||
content: `
|
content: `
|
||||||
.sleep-indicator {
|
.sleep-indicator {
|
||||||
@@ -656,6 +678,16 @@ class TestExecutor {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
}, { duration: command.milliseconds, message: command.message });
|
}, { duration: command.milliseconds, message: command.message });
|
||||||
|
} catch (error) {
|
||||||
|
// Ignore errors related to destroyed execution context
|
||||||
|
// This happens when the page navigates during sleep
|
||||||
|
if (error.message.includes('Execution context was destroyed') ||
|
||||||
|
error.message.includes('Target page, context or browser has been closed')) {
|
||||||
|
console.log('⚠️ Page navigated during sleep - skipping visual animation');
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@@ -663,7 +695,229 @@ class TestExecutor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async switchToNewWindow() {
|
async createStatusWindow() {
|
||||||
|
try {
|
||||||
|
// Create a separate browser context for the status window (opens in new window)
|
||||||
|
this.statusContext = await this.browser.newContext({
|
||||||
|
viewport: { width: 700, height: 500 }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a page in the new context (this will be in a separate window)
|
||||||
|
this.statusPage = await this.statusContext.newPage();
|
||||||
|
|
||||||
|
// Create the status window HTML
|
||||||
|
const statusHTML = `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>PlayWrong Test Status</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
color: white;
|
||||||
|
min-height: 100vh;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-bottom: 2px solid rgba(255,255,255,0.3);
|
||||||
|
padding-bottom: 15px;
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
.status-section {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
.status-title {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.current-command {
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
background: rgba(0,0,0,0.3);
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
word-break: break-all;
|
||||||
|
min-height: 80px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
.stats {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.stat {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.stat-number {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.stat-label {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
.progress-bar {
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.progress-fill {
|
||||||
|
background: #4CAF50;
|
||||||
|
height: 100%;
|
||||||
|
width: 0%;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
.status-indicator {
|
||||||
|
display: inline-block;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
.status-running { background: #4CAF50; animation: pulse 2s infinite; }
|
||||||
|
.status-waiting { background: #FF9800; }
|
||||||
|
.status-error { background: #F44336; }
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% { opacity: 1; }
|
||||||
|
50% { opacity: 0.5; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header">
|
||||||
|
<div class="logo">🎭 PlayWrong</div>
|
||||||
|
<div class="subtitle">Test Execution Status</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="status-section">
|
||||||
|
<div class="status-title">
|
||||||
|
<span id="status-indicator" class="status-indicator status-waiting"></span>
|
||||||
|
Current Command
|
||||||
|
</div>
|
||||||
|
<div id="current-command" class="current-command">Initializing...</div>
|
||||||
|
<div class="progress-bar">
|
||||||
|
<div id="progress-fill" class="progress-fill"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="status-section">
|
||||||
|
<div class="status-title">Statistics</div>
|
||||||
|
<div class="stats">
|
||||||
|
<div class="stat">
|
||||||
|
<span id="completed-count" class="stat-number">0</span>
|
||||||
|
<span class="stat-label">Completed</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat">
|
||||||
|
<span id="total-count" class="stat-number">0</span>
|
||||||
|
<span class="stat-label">Total</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat">
|
||||||
|
<span id="elapsed-time" class="stat-number">0s</span>
|
||||||
|
<span class="stat-label">Elapsed</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Load the status HTML
|
||||||
|
await this.statusPage.setContent(statusHTML);
|
||||||
|
|
||||||
|
// Initialize status tracking
|
||||||
|
this.startTime = Date.now();
|
||||||
|
this.completedCommands = 0;
|
||||||
|
this.totalCommands = 0;
|
||||||
|
|
||||||
|
console.log('🎭 PlayWrong status window created');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Failed to create status window:', error.message);
|
||||||
|
this.statusPage = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateStatus(command, isCompleted = false) {
|
||||||
|
if (!this.statusPage || this.headless) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if status page is still valid
|
||||||
|
if (this.statusPage.isClosed()) {
|
||||||
|
this.statusPage = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTime = Date.now();
|
||||||
|
const elapsedSeconds = Math.floor((currentTime - this.startTime) / 1000);
|
||||||
|
|
||||||
|
if (isCompleted) {
|
||||||
|
this.completedCommands++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const progress = this.totalCommands > 0 ? (this.completedCommands / this.totalCommands) * 100 : 0;
|
||||||
|
|
||||||
|
await this.statusPage.evaluate(({ command, completed, total, elapsed, progress }) => {
|
||||||
|
// Update current command
|
||||||
|
const commandEl = document.getElementById('current-command');
|
||||||
|
if (commandEl) commandEl.textContent = command;
|
||||||
|
|
||||||
|
// Update statistics
|
||||||
|
const completedEl = document.getElementById('completed-count');
|
||||||
|
if (completedEl) completedEl.textContent = completed;
|
||||||
|
|
||||||
|
const totalEl = document.getElementById('total-count');
|
||||||
|
if (totalEl) totalEl.textContent = total;
|
||||||
|
|
||||||
|
const elapsedEl = document.getElementById('elapsed-time');
|
||||||
|
if (elapsedEl) elapsedEl.textContent = elapsed + 's';
|
||||||
|
|
||||||
|
// Update progress bar
|
||||||
|
const progressEl = document.getElementById('progress-fill');
|
||||||
|
if (progressEl) progressEl.style.width = progress + '%';
|
||||||
|
|
||||||
|
// Update status indicator
|
||||||
|
const indicator = document.getElementById('status-indicator');
|
||||||
|
if (indicator) indicator.className = 'status-indicator status-running';
|
||||||
|
|
||||||
|
}, {
|
||||||
|
command: this.formatCommandForOutput(command),
|
||||||
|
completed: this.completedCommands,
|
||||||
|
total: this.totalCommands,
|
||||||
|
elapsed: elapsedSeconds,
|
||||||
|
progress: progress
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
// Silently ignore status window errors to not interfere with main test
|
||||||
|
// console.log('Status window update failed:', error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async followToNewWindow() {
|
||||||
console.log('🔄 Switching to new tab...');
|
console.log('🔄 Switching to new tab...');
|
||||||
|
|
||||||
// Get all current pages/tabs
|
// Get all current pages/tabs
|
||||||
@@ -755,8 +1009,8 @@ class TestExecutor {
|
|||||||
return `break "${command.message}"`;
|
return `break "${command.message}"`;
|
||||||
case 'sleep':
|
case 'sleep':
|
||||||
return command.message ? `sleep ${command.milliseconds} "${command.message}"` : `sleep ${command.milliseconds}`;
|
return command.message ? `sleep ${command.milliseconds} "${command.message}"` : `sleep ${command.milliseconds}`;
|
||||||
case 'switchToNewWindow':
|
case 'follow':
|
||||||
return 'switchToNewWindow';
|
return 'follow';
|
||||||
case 'switchToTab':
|
case 'switchToTab':
|
||||||
return `switchToTab tabIndex=${command.tabIndex}`;
|
return `switchToTab tabIndex=${command.tabIndex}`;
|
||||||
case 'extract':
|
case 'extract':
|
||||||
@@ -973,6 +1227,7 @@ class TestExecutor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Take screenshot of the main test page only (not status window)
|
||||||
await this.page.screenshot(screenshotOptions);
|
await this.page.screenshot(screenshotOptions);
|
||||||
|
|
||||||
// Restore viewport after screenshot
|
// Restore viewport after screenshot
|
||||||
@@ -992,7 +1247,7 @@ class TestExecutor {
|
|||||||
const keepElements = ['button', 'input', 'textarea', 'span', 'a'];
|
const keepElements = ['button', 'input', 'textarea', 'span', 'a'];
|
||||||
|
|
||||||
// Attributes we want to keep
|
// Attributes we want to keep
|
||||||
const keepAttributes = ['id', 'class', 'name', 'value', 'type'];
|
const keepAttributes = ['id', 'name', 'value', 'type'];
|
||||||
|
|
||||||
function processElement(element) {
|
function processElement(element) {
|
||||||
const tagName = element.tagName.toLowerCase();
|
const tagName = element.tagName.toLowerCase();
|
||||||
@@ -1221,6 +1476,20 @@ class TestExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async cleanup() {
|
async cleanup() {
|
||||||
|
if (this.statusPage && !this.headless) {
|
||||||
|
try {
|
||||||
|
await this.statusPage.close();
|
||||||
|
} catch (error) {
|
||||||
|
// Ignore errors when closing status window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.statusContext && !this.headless) {
|
||||||
|
try {
|
||||||
|
await this.statusContext.close();
|
||||||
|
} catch (error) {
|
||||||
|
// Ignore errors when closing status context
|
||||||
|
}
|
||||||
|
}
|
||||||
if (this.page) await this.page.close();
|
if (this.page) await this.page.close();
|
||||||
if (this.context) await this.context.close();
|
if (this.context) await this.context.close();
|
||||||
if (this.browser) await this.browser.close();
|
if (this.browser) await this.browser.close();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ class TestLinter {
|
|||||||
this.info = [];
|
this.info = [];
|
||||||
|
|
||||||
// Valid commands
|
// Valid commands
|
||||||
this.validCommands = ['use', 'open', 'wait', 'click', 'scroll', 'fill', 'break', 'sleep', 'dump', 'switchToNewWindow', 'switchToTab', 'extract'];
|
this.validCommands = ['use', 'open', 'wait', 'click', 'scroll', 'fill', 'break', 'sleep', 'dump', 'follow', 'switchToTab', 'extract'];
|
||||||
|
|
||||||
// Valid HTML elements
|
// Valid HTML elements
|
||||||
this.validElements = [
|
this.validElements = [
|
||||||
@@ -30,7 +30,7 @@ class TestLinter {
|
|||||||
'break': [],
|
'break': [],
|
||||||
'sleep': ['milliseconds'],
|
'sleep': ['milliseconds'],
|
||||||
'dump': ['name'],
|
'dump': ['name'],
|
||||||
'switchToNewWindow': [],
|
'follow': [],
|
||||||
'switchToTab': ['tabIndex'],
|
'switchToTab': ['tabIndex'],
|
||||||
'extract': ['element', 'attribute']
|
'extract': ['element', 'attribute']
|
||||||
};
|
};
|
||||||
@@ -256,11 +256,7 @@ class TestLinter {
|
|||||||
const command = line.cleaned.split(' ')[0];
|
const command = line.cleaned.split(' ')[0];
|
||||||
|
|
||||||
// Handle multi-word commands
|
// Handle multi-word commands
|
||||||
if (line.cleaned.startsWith('switch to new window')) {
|
if (line.cleaned.startsWith('follow')) {
|
||||||
continue; // This is valid
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.cleaned.startsWith('extract ')) {
|
|
||||||
continue; // This is valid
|
continue; // This is valid
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,6 +264,10 @@ class TestLinter {
|
|||||||
continue; // This is valid
|
continue; // This is valid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line.cleaned.startsWith('extract ')) {
|
||||||
|
continue; // This is valid
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.validCommands.includes(command)) {
|
if (!this.validCommands.includes(command)) {
|
||||||
this.addError(`Invalid command '${command}'. Valid commands: ${this.validCommands.join(', ')}`, line.lineNumber);
|
this.addError(`Invalid command '${command}'. Valid commands: ${this.validCommands.join(', ')}`, line.lineNumber);
|
||||||
}
|
}
|
||||||
@@ -332,6 +332,12 @@ class TestLinter {
|
|||||||
if (!line.cleaned.match(/\d+/)) {
|
if (!line.cleaned.match(/\d+/)) {
|
||||||
this.addError(`Command '${command}' requires numeric tabIndex`, line.lineNumber);
|
this.addError(`Command '${command}' requires numeric tabIndex`, line.lineNumber);
|
||||||
}
|
}
|
||||||
|
} else if (reqParam === 'attribute' && command === 'extract') {
|
||||||
|
// Special handling for extract command - attribute is part of command syntax
|
||||||
|
const extractMatch = line.cleaned.match(/extract\s+(\w+)\s+from\s+(.+?)\s+to\s+"([^"]+)"/);
|
||||||
|
if (!extractMatch) {
|
||||||
|
this.addError(`Command '${command}' has invalid syntax. Expected: extract <attribute> from <selector> to "<variable>"`, line.lineNumber);
|
||||||
|
}
|
||||||
} else if (!params[reqParam]) {
|
} else if (!params[reqParam]) {
|
||||||
this.addError(`Command '${command}' missing required parameter '${reqParam}'`, line.lineNumber);
|
this.addError(`Command '${command}' missing required parameter '${reqParam}'`, line.lineNumber);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,10 +186,10 @@ class TestParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse switch to new window command
|
// Parse follow command (previously switch to new window)
|
||||||
if (line.startsWith('switch to new window')) {
|
if (line.startsWith('follow')) {
|
||||||
return {
|
return {
|
||||||
type: 'switchToNewWindow'
|
type: 'follow'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,9 +204,9 @@ class TestParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse extract command: extract href from element=a target="_blank" to variable="ORDER_URL"
|
// Parse extract command: extract href from element=a childText="text" to "ORDER_URL"
|
||||||
if (line.startsWith('extract ')) {
|
if (line.startsWith('extract ')) {
|
||||||
const match = line.match(/extract\s+(\w+)\s+from\s+(.+?)\s+to\s+variable="([^"]+)"/);
|
const match = line.match(/extract\s+(\w+)\s+from\s+(.+?)\s+to\s+"([^"]+)"/);
|
||||||
if (match) {
|
if (match) {
|
||||||
const attribute = match[1];
|
const attribute = match[1];
|
||||||
const selectorPart = match[2];
|
const selectorPart = match[2];
|
||||||
|
|||||||
43
step1.test
43
step1.test
@@ -9,7 +9,7 @@ Part 3: Login to the email account
|
|||||||
use "Chrome"
|
use "Chrome"
|
||||||
|
|
||||||
# Part 1 - Load Growheads, put one item in the cart and go to checkout
|
# Part 1 - Load Growheads, put one item in the cart and go to checkout
|
||||||
/*open "https://growheads.de"
|
open "https://dev.seedheads.de"
|
||||||
sleep 2000 "page load"
|
sleep 2000 "page load"
|
||||||
wait element=a href=/Kategorie/Seeds
|
wait element=a href=/Kategorie/Seeds
|
||||||
click element=a href=/Kategorie/Seeds
|
click element=a href=/Kategorie/Seeds
|
||||||
@@ -63,7 +63,7 @@ sleep 1000 "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 3000 "order completion"
|
sleep 3000 "order completion"
|
||||||
*/
|
|
||||||
# Part 3 - Login to the email account
|
# Part 3 - Login to the email account
|
||||||
open "https://mail.growbnb.de/"
|
open "https://mail.growbnb.de/"
|
||||||
sleep 100 "page load"
|
sleep 100 "page load"
|
||||||
@@ -89,33 +89,38 @@ sleep 300 "mehr button click"
|
|||||||
# Click on "In neuem Fenster öffnen" link
|
# Click on "In neuem Fenster öffnen" link
|
||||||
wait element=a id="rcmbtn134"
|
wait element=a id="rcmbtn134"
|
||||||
click element=a id="rcmbtn134"
|
click element=a id="rcmbtn134"
|
||||||
sleep 3000 "new window open"
|
|
||||||
|
|
||||||
# Switch to the new window that was opened
|
# Switch to the new window that was opened
|
||||||
switch to new window
|
follow
|
||||||
|
|
||||||
# Wait a bit more for the new window to fully load
|
|
||||||
sleep 2000 "new window load"
|
|
||||||
|
|
||||||
# Verify that "Musteranmerkung" exists in the content
|
# Verify that "Musteranmerkung" exists in the content
|
||||||
wait element=p childText="Musteranmerkung"
|
wait element=p childText="Musteranmerkung"
|
||||||
|
|
||||||
# Extract the order URL from the link
|
# Extract the order URL from the link
|
||||||
extract href from element=a childText="https://growheads.de/profile#W-" to variable="ORDER_URL"
|
extract href from element=a childText="https://dev.seedheads.de/profile#W-" to "ORDER_URL"
|
||||||
|
|
||||||
sleep 300 "bestellbestätigung click"
|
|
||||||
dump "after_bestellbestaetigung_click"
|
|
||||||
sleep 3000 "bestellbestätigung click"
|
|
||||||
# Delete the email by clicking "Löschen"
|
|
||||||
wait element=a id="rcmbtn105"
|
wait element=a id="rcmbtn105"
|
||||||
click element=a id="rcmbtn105"
|
click element=a id="rcmbtn105"
|
||||||
sleep 1000 "email deleted"
|
sleep 300 "email deleted"
|
||||||
|
|
||||||
# Now open the extracted URL
|
# Now open the extracted URL
|
||||||
open "$ORDER_URL"
|
open "$ORDER_URL"
|
||||||
sleep 2000 "order page load"
|
wait element=input type="email"
|
||||||
dump "order_page_from_extracted_url"
|
fill element=input type="email" value="autotest@growheads.de"
|
||||||
|
sleep 200 "email fill"
|
||||||
dump "after_new_window_click"
|
wait element=input type="password"
|
||||||
|
fill element=input type="password" value="$PASSWORD"
|
||||||
sleep 30000 "login submit"
|
sleep 200 "password fill"
|
||||||
|
wait element=button childText="ANMELDEN" class="MuiButton-fullWidth"
|
||||||
|
click element=button childText="ANMELDEN" class="MuiButton-fullWidth"
|
||||||
|
sleep 300 "anmelden click"
|
||||||
|
wait element=button childText="Schließen"
|
||||||
|
click element=button childText="Schließen"
|
||||||
|
sleep 100 "schließen click"
|
||||||
|
wait element=button class="MuiIconButton-colorError"
|
||||||
|
click element=button class="MuiIconButton-colorError"
|
||||||
|
sleep 100 "stornieren click"
|
||||||
|
wait element=button childText="Stornieren"
|
||||||
|
click element=button childText="Stornieren"
|
||||||
|
sleep 100 "stornieren click"
|
||||||
|
sleep 10000 "completed"
|
||||||
Reference in New Issue
Block a user