Add manual SDK tests (#4555)

This commit is contained in:
Stanislav Novosad
2026-01-26 15:43:53 -07:00
committed by GitHub
parent a43b3ae3cc
commit 72b9fe960f
19 changed files with 3037 additions and 1 deletions

65
tests/sdk/web/click.html Normal file
View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Click Counter</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 20px;
text-align: center;
background-color: #121212;
color: #f5f5f5;
}
h1 {
color: #f5f5f5;
}
button {
padding: 20px 40px;
font-size: 18px;
background-color: #2563eb;
color: #f5f5f5;
border: 1px solid #1d4ed8;
border-radius: 8px;
cursor: pointer;
margin: 30px 0;
transition: background-color 0.3s, transform 0.1s;
box-shadow: 0 10px 25px rgba(37, 99, 235, 0.25);
}
button:hover {
background-color: #1d4ed8;
}
button:active {
transform: scale(0.98);
}
#counter {
margin-top: 30px;
font-size: 24px;
font-weight: bold;
color: #86efac;
min-height: 50px;
}
</style>
</head>
<body>
<h1>Click Counter</h1>
<button id="button">Click Me!</button>
<div id="counter">Button clicked 0 times</div>
<script>
let clickCount = 0;
const clickBtn = document.getElementById('button');
const counter = document.getElementById('counter');
clickBtn.addEventListener('click', function() {
clickCount++;
counter.textContent = `Button clicked ${clickCount} times`;
});
</script>
</body>
</html>

View File

@@ -0,0 +1,98 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dark Theme Select</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 20px 30px;
background-color: #121212;
color: #f5f5f5;
line-height: 1.6;
}
h1 {
color: #f5f5f5;
text-align: center;
}
form {
display: flex;
flex-direction: column;
gap: 20px;
margin: 30px 0;
padding: 30px;
background-color: #1e1e1e;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
}
label {
font-weight: 600;
color: #e0e0e0;
}
select {
padding: 12px;
font-size: 16px;
border-radius: 8px;
border: 1px solid #2d2d2d;
background-color: #1b1b1b;
color: #f5f5f5;
appearance: none;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
select:focus {
outline: none;
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.35);
}
input[type="submit"] {
align-self: flex-start;
padding: 12px 24px;
font-size: 16px;
background-color: #2563eb;
color: #f5f5f5;
border: 1px solid #1d4ed8;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s, transform 0.1s;
box-shadow: 0 10px 25px rgba(37, 99, 235, 0.25);
}
input[type="submit"]:hover {
background-color: #1d4ed8;
}
input[type="submit"]:active {
transform: scale(0.98);
}
p {
color: #d1d1d1;
text-align: center;
}
a {
color: #93c5fd;
}
</style>
</head>
<body>
<h1>The select element</h1>
<p>The select element is used to create a drop-down list.</p>
<form action="/action_page.php">
<label for="cars">Choose a car:</label>
<select name="cars" id="cars">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
</select>
<input type="submit" value="Submit">
</form>
<p>Click the "Submit" button and the form-data will be sent to a page on the
server called "action_page.php".</p>
</body>
</html>

View File

@@ -0,0 +1,169 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Download</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 20px;
text-align: center;
background-color: #121212;
color: #f5f5f5;
}
h1 {
color: #f5f5f5;
}
.container {
margin: 40px 0;
}
button {
padding: 20px 40px;
font-size: 18px;
background-color: #2563eb;
color: #f5f5f5;
border: 1px solid #1d4ed8;
border-radius: 8px;
cursor: pointer;
margin: 10px;
transition: background-color 0.3s, transform 0.1s;
box-shadow: 0 10px 25px rgba(37, 99, 235, 0.25);
}
button:hover {
background-color: #1d4ed8;
}
button:active {
transform: scale(0.98);
}
#status {
margin-top: 30px;
font-size: 18px;
color: #86efac;
min-height: 30px;
}
.description {
color: #9ca3af;
margin-bottom: 20px;
}
</style>
</head>
<body>
<h1>File Download Test</h1>
<p class="description">Click the button below to download a sample PDF file</p>
<div class="container">
<button id="downloadBtn">Download PDF Report</button>
</div>
<div id="status"></div>
<script>
const downloadBtn = document.getElementById('downloadBtn');
const status = document.getElementById('status');
// Generate a simple PDF content
function generatePDF() {
// Create a simple PDF structure with text content
const pdfContent = `%PDF-1.4
1 0 obj
<<
/Type /Catalog
/Pages 2 0 R
>>
endobj
2 0 obj
<<
/Type /Pages
/Kids [3 0 R]
/Count 1
>>
endobj
3 0 obj
<<
/Type /Page
/Parent 2 0 R
/Resources <<
/Font <<
/F1 <<
/Type /Font
/Subtype /Type1
/BaseFont /Helvetica
>>
>>
>>
/MediaBox [0 0 612 792]
/Contents 4 0 R
>>
endobj
4 0 obj
<<
/Length 110
>>
stream
BT
/F1 24 Tf
50 700 Td
(Sample PDF Report) Tj
0 -50 Td
/F1 12 Tf
(Generated by Skyvern Test) Tj
0 -30 Td
(This is a test PDF file for download automation.) Tj
ET
endstream
endobj
xref
0 5
0000000000 65535 f
0000000009 00000 n
0000000058 00000 n
0000000115 00000 n
0000000317 00000 n
trailer
<<
/Size 5
/Root 1 0 R
>>
startxref
476
%%EOF`;
return pdfContent;
}
downloadBtn.addEventListener('click', function() {
// Generate PDF content
const pdfContent = generatePDF();
// Create a Blob from the PDF content
const blob = new Blob([pdfContent], { type: 'application/pdf' });
// Create a download link
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'sample_report.pdf';
// Trigger download
document.body.appendChild(a);
a.click();
// Clean up
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 100);
// Update status
status.textContent = 'PDF downloaded successfully!';
status.style.color = '#86efac';
setTimeout(() => {
status.textContent = '';
}, 3000);
});
</script>
</body>
</html>

110
tests/sdk/web/input.html Normal file
View File

@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Text Input Demo</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 20px;
text-align: center;
background-color: #121212;
color: #f5f5f5;
}
h1 {
color: #f5f5f5;
}
.input-container {
margin: 30px 0;
padding: 25px;
background-color: #1e1e1e;
border-radius: 12px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
display: inline-flex;
gap: 12px;
}
input[type="text"] {
padding: 12px 14px;
font-size: 16px;
width: 300px;
border: 1px solid #2d2d2d;
border-radius: 8px;
background-color: #1b1b1b;
color: #f5f5f5;
}
input[type="text"]::placeholder {
color: #9ca3af;
}
input[type="text"]:focus {
outline: none;
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.35);
}
button {
padding: 12px 24px;
font-size: 16px;
background-color: #2563eb;
color: #f5f5f5;
border: 1px solid #1d4ed8;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s, transform 0.1s;
box-shadow: 0 10px 25px rgba(37, 99, 235, 0.25);
}
button:hover {
background-color: #1d4ed8;
}
button:active {
transform: scale(0.98);
}
#output {
margin-top: 30px;
padding: 20px;
font-size: 24px;
font-weight: bold;
color: #86efac;
min-height: 50px;
background-color: #1e1e1e;
border-radius: 12px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.35);
}
</style>
</head>
<body>
<h1>Enter Your Name</h1>
<div class="input-container">
<input type="text" id="nameInput" placeholder="Type your name here...">
<button id="submitBtn">Submit</button>
</div>
<div id="output"></div>
<script>
const nameInput = document.getElementById('nameInput');
const submitBtn = document.getElementById('submitBtn');
const output = document.getElementById('output');
function showGreeting() {
const name = nameInput.value.trim();
if (name) {
output.textContent = `Hello, ${name}!`;
} else {
output.textContent = 'Please enter a name!';
}
}
submitBtn.addEventListener('click', showGreeting);
// Allow pressing Enter to submit
nameInput.addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
showGreeting();
}
});
</script>
</body>
</html>

308
tests/sdk/web/login.html Normal file
View File

@@ -0,0 +1,308 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Demo</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 20px;
text-align: center;
background-color: #121212;
color: #f5f5f5;
}
h1 {
color: #f5f5f5;
}
.view {
display: none;
}
.view.active {
display: block;
}
.form-container {
margin: 30px 0;
padding: 30px;
background-color: #1e1e1e;
border-radius: 12px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
}
.input-group {
margin: 20px 0;
text-align: left;
}
label {
display: block;
margin-bottom: 8px;
font-size: 14px;
font-weight: 500;
color: #d1d5db;
}
input[type="text"],
input[type="password"] {
padding: 12px 14px;
font-size: 16px;
width: 100%;
box-sizing: border-box;
border: 1px solid #2d2d2d;
border-radius: 8px;
background-color: #1b1b1b;
color: #f5f5f5;
}
input[type="text"]::placeholder,
input[type="password"]::placeholder {
color: #9ca3af;
}
input[type="text"]:focus,
input[type="password"]:focus {
outline: none;
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.35);
}
button {
padding: 12px 24px;
font-size: 16px;
background-color: #2563eb;
color: #f5f5f5;
border: 1px solid #1d4ed8;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s, transform 0.1s;
box-shadow: 0 10px 25px rgba(37, 99, 235, 0.25);
margin: 10px 5px;
}
button:hover {
background-color: #1d4ed8;
}
button:active {
transform: scale(0.98);
}
button.secondary {
background-color: #374151;
border: 1px solid #4b5563;
box-shadow: 0 10px 25px rgba(55, 65, 81, 0.25);
}
button.secondary:hover {
background-color: #4b5563;
}
.error {
margin-top: 15px;
padding: 12px;
background-color: rgba(239, 68, 68, 0.15);
border: 1px solid rgba(239, 68, 68, 0.3);
border-radius: 8px;
color: #fca5a5;
font-size: 14px;
}
.welcome {
margin: 30px 0;
padding: 20px;
font-size: 20px;
color: #86efac;
background-color: #1e1e1e;
border-radius: 12px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.35);
}
.account-info {
margin: 30px 0;
padding: 25px;
background-color: #1e1e1e;
border-radius: 12px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
text-align: left;
}
.info-row {
display: flex;
justify-content: space-between;
padding: 12px 0;
border-bottom: 1px solid #2d2d2d;
}
.info-row:last-child {
border-bottom: none;
}
.info-label {
font-weight: 500;
color: #9ca3af;
}
.info-value {
color: #f5f5f5;
}
.click-section {
margin: 30px 0;
padding: 20px;
background-color: #1e1e1e;
border-radius: 12px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.35);
}
.click-counter {
margin-top: 15px;
font-size: 20px;
font-weight: bold;
color: #86efac;
}
</style>
</head>
<body>
<!-- Login View -->
<div id="loginView" class="view active">
<h1>Login</h1>
<div class="form-container">
<div class="input-group">
<label for="username">Username</label>
<input type="text" id="username" placeholder="Enter username">
</div>
<div class="input-group">
<label for="password">Password</label>
<input type="password" id="password" placeholder="Enter password">
</div>
<button id="loginBtn">Login</button>
<div id="errorMessage" class="error" style="display: none;"></div>
</div>
</div>
<!-- Main View -->
<div id="mainView" class="view">
<h1>Dashboard</h1>
<div class="welcome" id="welcomeMessage"></div>
<button id="accountBtn">Account</button>
<button id="logoutBtn" class="secondary">Logout</button>
</div>
<!-- Account View -->
<div id="accountView" class="view">
<h1>Account Information</h1>
<div class="account-info">
<div class="info-row">
<span class="info-label">Username:</span>
<span class="info-value" id="accountUsername"></span>
</div>
<div class="info-row">
<span class="info-label">Email:</span>
<span class="info-value" id="accountEmail"></span>
</div>
<div class="info-row">
<span class="info-label">Member Since:</span>
<span class="info-value" id="accountMemberSince"></span>
</div>
<div class="info-row">
<span class="info-label">Account Type:</span>
<span class="info-value" id="accountType"></span>
</div>
</div>
<div class="click-section">
<button id="clickMeBtn">Click Me</button>
<div id="clickCounter" class="click-counter">Button clicked 0 times</div>
</div>
<button id="backBtn" class="secondary">Back to Dashboard</button>
<button id="logoutFromAccountBtn" class="secondary">Logout</button>
</div>
<script>
// In-memory state
let currentUser = null;
let clickCount = 0;
// Views
const loginView = document.getElementById('loginView');
const mainView = document.getElementById('mainView');
const accountView = document.getElementById('accountView');
// Login elements
const usernameInput = document.getElementById('username');
const passwordInput = document.getElementById('password');
const loginBtn = document.getElementById('loginBtn');
const errorMessage = document.getElementById('errorMessage');
// Main view elements
const welcomeMessage = document.getElementById('welcomeMessage');
const accountBtn = document.getElementById('accountBtn');
const logoutBtn = document.getElementById('logoutBtn');
// Account view elements
const accountUsername = document.getElementById('accountUsername');
const accountEmail = document.getElementById('accountEmail');
const accountMemberSince = document.getElementById('accountMemberSince');
const accountType = document.getElementById('accountType');
const clickMeBtn = document.getElementById('clickMeBtn');
const clickCounter = document.getElementById('clickCounter');
const backBtn = document.getElementById('backBtn');
const logoutFromAccountBtn = document.getElementById('logoutFromAccountBtn');
// Fake user data
const validCredentials = {
username: 'testlogin',
password: 'testpassword',
email: 'testlogin@example.com',
memberSince: 'January 2024',
accountType: 'Premium'
};
function showView(view) {
loginView.classList.remove('active');
mainView.classList.remove('active');
accountView.classList.remove('active');
view.classList.add('active');
}
function login() {
const username = usernameInput.value.trim();
const password = passwordInput.value;
if (username === validCredentials.username && password === validCredentials.password) {
currentUser = validCredentials;
welcomeMessage.textContent = `Welcome back, ${currentUser.username}!`;
errorMessage.style.display = 'none';
usernameInput.value = '';
passwordInput.value = '';
showView(mainView);
} else {
errorMessage.textContent = 'Invalid username or password';
errorMessage.style.display = 'block';
}
}
function logout() {
currentUser = null;
showView(loginView);
}
function showAccount() {
if (currentUser) {
accountUsername.textContent = currentUser.username;
accountEmail.textContent = currentUser.email;
accountMemberSince.textContent = currentUser.memberSince;
accountType.textContent = currentUser.accountType;
showView(accountView);
}
}
// Event listeners
loginBtn.addEventListener('click', login);
usernameInput.addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
login();
}
});
passwordInput.addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
login();
}
});
accountBtn.addEventListener('click', showAccount);
backBtn.addEventListener('click', () => showView(mainView));
logoutBtn.addEventListener('click', logout);
logoutFromAccountBtn.addEventListener('click', logout);
clickMeBtn.addEventListener('click', function() {
clickCount++;
clickCounter.textContent = `Button clicked ${clickCount} times`;
});
</script>
</body>
</html>

101
tests/sdk/web/upload.html Normal file
View File

@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Upload</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 50px auto;
padding: 20px;
text-align: center;
background-color: #121212;
color: #f5f5f5;
}
h1 {
color: #f5f5f5;
}
.upload-container {
margin: 30px 0;
padding: 40px;
border: 2px dashed #3f3f3f;
border-radius: 12px;
background-color: #1e1e1e;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
input[type="file"] {
padding: 10px;
font-size: 16px;
cursor: pointer;
color: #f5f5f5;
}
input[type="file"]::-webkit-file-upload-button {
padding: 10px 18px;
font-size: 14px;
background-color: #2563eb;
color: #f5f5f5;
border: 1px solid #1d4ed8;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s, transform 0.1s;
}
input[type="file"]::-webkit-file-upload-button:hover {
background-color: #1d4ed8;
}
input[type="file"]::-webkit-file-upload-button:active {
transform: scale(0.98);
}
#preview {
margin-top: 30px;
background-color: #1e1e1e;
border-radius: 12px;
padding: 30px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
#preview img {
max-width: 100%;
max-height: 500px;
border-radius: 8px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
.hidden {
display: none;
}
</style>
</head>
<body>
<h1>Upload an Image</h1>
<div class="upload-container">
<input type="file" id="imageUpload" accept="image/*">
</div>
<div id="preview" class="hidden">
<h2>Your Image:</h2>
<img id="uploadedImage" src="" alt="Uploaded image">
</div>
<script>
const fileInput = document.getElementById('imageUpload');
const preview = document.getElementById('preview');
const uploadedImage = document.getElementById('uploadedImage');
fileInput.addEventListener('change', function(event) {
const file = event.target.files[0];
if (file && file.type.startsWith('image/')) {
const reader = new FileReader();
reader.onload = function(e) {
uploadedImage.src = e.target.result;
preview.classList.remove('hidden');
};
reader.readAsDataURL(file);
}
});
</script>
</body>
</html>