Skip to content

Commit

Permalink
Adding MVP custom form validation (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
DiogenesAnalytics committed Mar 14, 2024
1 parent 2245d4f commit b93298b
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 38 deletions.
97 changes: 70 additions & 27 deletions scripts/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function handleFileUpload(event, formData, callback) {
// Wait for all promises to resolve
Promise.all(promises).then(() => {
// Debug statement: Indicate that all file uploads are completed
console.log("All file uploads completed");
console.log("All file uploads completed!");

// Invoke the callback with the updated formData object
callback(formData);
Expand Down Expand Up @@ -114,7 +114,7 @@ function generateHtmlContent(formData) {
// Handle multiple file data URLs and the correct tag for the MIME type
formData[key].forEach(url => {
// log file
console.log("Adding to Download HTML: " + url)
console.log("Embedding file into HTML: " + url)
// Get MIME type of the file
const mimeType = url.split(';')[0].split(':')[1];

Expand Down Expand Up @@ -330,6 +330,66 @@ fetch('config.json')
send_button.setAttribute('id', 'send_button'); // Add id attribute
form.appendChild(send_button);

// Custom validation
send_button.addEventListener('click', function(event) {
// Prevent the default form submission behavior
event.preventDefault();

// Check if the form element is selected correctly
const contactForm = document.getElementById("contact-form");
const inputs = contactForm.querySelectorAll('input, textarea, select');
let customValidationFailed = false;

// Log to console
console.log("Beginning custom form validation");

// Begin input checking ...
inputs.forEach(input => {
let fieldValue = input.value;

if (input.tagName === 'SELECT') {
if (input.hasAttribute('multiple')) {
// Handle <select multiple> elements
const selectedOptions = Array.from(input.selectedOptions);
const selectedValues = selectedOptions.map(option => option.value);

// Check if any selected option has an empty string value
if (selectedValues.includes('')) {
fieldValue = ''; // Set fieldValue to an empty string
}
} else {
// Handle single-selection <select> elements
fieldValue = input.value;
}
}

if (input.hasAttribute('required') && (!fieldValue || !fieldValue.trim())) {
// Highlight required fields in red
input.style.borderColor = 'red';

// Set the flag to indicate custom validation failure
customValidationFailed = true;
} else {
input.style.borderColor = '#555'; // Reset border color
}
});

if (customValidationFailed) {
console.log("Validation failed.")
alert('Please fill out all required fields.');
return; // Exit the function without submitting the form
}

// If custom validation passes, manually submit the form
if (contactForm.reportValidity()) {
console.log("Validation passed. Submitting form...");
contactForm.submit();
}
else {
console.log("Validation failed. Builtin validation triggered...");
}
});

// Setup form download button
const download_html_button = document.createElement('button');
download_html_button.setAttribute('type', 'button');
Expand All @@ -338,10 +398,15 @@ fetch('config.json')

// Add event to listen for click
download_html_button.addEventListener('click', () => {

// Get inputs to store
const formData = {};
const inputs = form.querySelectorAll('input, textarea, select');
let valid = true;

// Log to console
console.log("Beginning download validation");

inputs.forEach(input => {
let fieldValue = input.value;

Expand All @@ -364,6 +429,9 @@ fetch('config.json')
});

if (valid) {
// Log to console
console.log("Validation passed. Downloading form...");

// Initialize an array to store all promises
const promises = [];

Expand All @@ -382,9 +450,6 @@ fetch('config.json')

// Wait for all promises to resolve
Promise.all(promises).then(() => {
// All file uploads are completed
console.log("After handleFileUpload: " + JSON.stringify(formData));

// Generate HTML content
const htmlContent = generateHtmlContent(formData);

Expand Down Expand Up @@ -416,25 +481,3 @@ fetch('config.json')
.catch(error => {
handleConfigError(error);
});

// Custom validation for select elements
document.getElementById("contact-form").addEventListener("submit", function(event) {
if (!this.checkValidity()) {
// Built-in validation failed, no need to continue
return;
}

// Custom validation for select elements
var selectElements = this.querySelectorAll("select[required]");
for (var i = 0; i < selectElements.length; i++) {
if (selectElements[i].value === "") {
event.preventDefault(); // Prevent form submission
alert("Please select an option.");

// Scroll to the element
selectElements[i].scrollIntoView({ behavior: "smooth", block: "center" });

return;
}
}
});
1 change: 0 additions & 1 deletion tests/test_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ def test_serve_scripts_route(session_web_app: Flask) -> None:
assert response.status_code == 200


@pytest.mark.debug
@pytest.mark.flask
@pytest.mark.fixture
def test_submit_form_route(
Expand Down
21 changes: 11 additions & 10 deletions tests/test_website.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,20 +365,21 @@ def test_form_submission_required_constraint(
# store page source before
page_source = {"before": sb.get_page_source()}

# check for required questions
required_questions_present = any_required_questions(config["questions"])

# ... now click it
send_button.click()

# check alert message
if required_questions_present:
sb.wait_for_and_accept_alert()

# now store it after
page_source["after"] = sb.get_page_source()

# now check appropriate behavior
if any_required_questions(config["questions"]):
# should NOT see contact form response
assert page_source["before"] == page_source["after"]

else:
# should see contact form response
sb.assert_text("Contact Form Response")
# should see red outlined required questions
assert all(check_required_inputs_border_red(page_source["after"]))

# save screenshot for confirmation
sb.save_screenshot_to_logs()
Expand Down Expand Up @@ -615,10 +616,10 @@ def test_select_default_submission_rejected(
sb.accept_alert()

# make sure alert texts match
assert alert_text == "Please select an option."
assert alert_text == "Please fill out all required fields."

# now store it after
page_source["after"] = sb.get_page_source()

# should NOT see contact form response
assert page_source["before"] == page_source["after"]
assert "Contact Form Response" not in page_source["after"]

0 comments on commit b93298b

Please sign in to comment.