Skip to main content
Glama
submissions.test.js12.5 kB
/** * Submissions and Notifications Tests for Gravity MCP * Tests form submission workflow, validation, and notifications */ import GravityFormsClient from '../gravity-forms-client.js'; import { TestRunner, TestAssert, MockHttpClient, MockResponse, setupTestEnvironment, generateMockEntry } from './helpers.js'; const suite = new TestRunner('Submissions and Notifications Tests'); let client; let mockHttpClient; let testEnv; suite.beforeEach(() => { testEnv = setupTestEnvironment(); mockHttpClient = new MockHttpClient(); client = new GravityFormsClient(testEnv); client.httpClient = mockHttpClient; mockHttpClient.setMockResponse('GET', '/forms', new MockResponse({ forms: [] })); }); // ================================= // SUBMIT FORM DATA TESTS // ================================= suite.test('Submit Form: Should submit form successfully', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: true, entry_id: 500, confirmation_message: '<p>Thank you for your submission!</p>', validation_messages: {} })); const result = await client.submitFormData({ form_id: 1, input_1: 'John Doe', input_2: 'john@example.com', input_3: 'This is my message' }); TestAssert.isTrue(result.success); TestAssert.equal(result.entry_id, 500); TestAssert.includes(result.confirmation_message, 'Thank you'); TestAssert.equal(result.message, 'Form submitted successfully'); }); suite.test('Submit Form: Should handle validation errors', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: false, validation_messages: { '1': 'Name is required', '2': 'Please enter a valid email address' } })); const result = await client.submitFormData({ form_id: 1, input_3: 'Only message provided' }); TestAssert.isFalse(result.success); TestAssert.equal(result.validation_messages['1'], 'Name is required'); TestAssert.equal(result.message, 'Submission failed validation'); }); suite.test('Submit Form: Should include field values', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: true, entry_id: 600 })); const result = await client.submitFormData({ form_id: 1, input_1: 'Jane Smith', input_2: 'jane@example.com', field_values: { utm_source: 'google', utm_campaign: 'summer2024', referrer: 'https://example.com' } }); TestAssert.isTrue(result.success); TestAssert.equal(result.entry_id, 600); }); suite.test('Submit Form: Should handle multi-page form submission', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: true, page_number: 2, source_page_number: 1, is_last_page: false, confirmation_message: '' })); const result = await client.submitFormData({ form_id: 1, input_1: 'Page 1 data', source_page_number: 1, target_page_number: 2 }); // Multi-page progression doesn't complete submission TestAssert.isTrue(result.success); TestAssert.isNull(result.entry_id || null); }); suite.test('Submit Form: Should handle file upload fields', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: true, entry_id: 700, uploaded_files: { 'input_5': 'https://example.com/uploads/file.pdf' } })); const result = await client.submitFormData({ form_id: 1, input_1: 'John', input_5: 'file.pdf' // File upload field }); TestAssert.isTrue(result.success); TestAssert.equal(result.entry_id, 700); }); suite.test('Submit Form: Should handle conditional logic', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: true, entry_id: 800, evaluated_conditional_logic: { '3': { is_visible: false }, '4': { is_visible: true } } })); const result = await client.submitFormData({ form_id: 1, input_1: 'trigger_value', input_4: 'Conditional field shown' }); TestAssert.isTrue(result.success); TestAssert.equal(result.entry_id, 800); }); suite.test('Submit Form: Should require form_id', async () => { await TestAssert.throwsAsync( () => client.submitFormData({ input_1: 'Test' }), 'form_id is required', 'Should require form_id' ); }); // ================================= // VALIDATE SUBMISSION TESTS // ================================= suite.test('Validate Submission: Should validate without processing', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: true, validation_messages: {} })); const result = await client.validateSubmission({ form_id: 1, input_1: 'John Doe', input_2: 'john@example.com' }); TestAssert.isTrue(result.valid); TestAssert.equal(result.message, 'Submission data is valid'); }); suite.test('Validate Submission: Should return field-specific errors', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: false, validation_messages: { '2': 'Email is invalid', '3': 'Message must be at least 10 characters' }, field_errors: [ { field_id: '2', message: 'Email is invalid' }, { field_id: '3', message: 'Message must be at least 10 characters' } ] })); const result = await client.validateSubmission({ form_id: 1, input_1: 'John', input_2: 'not-an-email', input_3: 'Short' }); TestAssert.isFalse(result.valid); TestAssert.lengthOf(result.field_errors, 2); TestAssert.equal(result.field_errors[0].field_id, '2'); TestAssert.equal(result.message, 'Validation errors found'); }); suite.test('Validate Submission: Should validate required fields', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: false, validation_messages: { '1': 'This field is required', '2': 'This field is required' } })); const result = await client.validateSubmission({ form_id: 1, input_3: 'Only optional field filled' }); TestAssert.isFalse(result.valid); TestAssert.equal(result.validation_messages['1'], 'This field is required'); }); suite.test('Validate Submission: Should validate field formats', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: false, validation_messages: { '4': 'Please enter a valid phone number', '5': 'Please enter a valid URL', '6': 'Please enter a valid date' } })); const result = await client.validateSubmission({ form_id: 1, input_4: '123', input_5: 'not-a-url', input_6: 'invalid-date' }); TestAssert.isFalse(result.valid); TestAssert.includes(result.validation_messages['4'], 'phone'); TestAssert.includes(result.validation_messages['5'], 'URL'); TestAssert.includes(result.validation_messages['6'], 'date'); }); // ================================= // SEND NOTIFICATIONS TESTS // ================================= suite.test('Send Notifications: Should send all notifications for entry', async () => { mockHttpClient.setMockResponse('POST', '/entries/100/notifications', new MockResponse({ notifications_sent: ['admin_notification', 'user_notification'] })); const result = await client.sendNotifications({ entry_id: 100 }); TestAssert.isTrue(result.sent); TestAssert.equal(result.entry_id, 100); TestAssert.lengthOf(result.notifications_sent, 2); TestAssert.equal(result.message, 'Notifications sent successfully'); }); suite.test('Send Notifications: Should send specific notifications', async () => { mockHttpClient.setMockResponse('POST', '/entries/100/notifications', new MockResponse({ notifications_sent: ['admin_notification'] })); const result = await client.sendNotifications({ entry_id: 100, notification_ids: ['admin_notification'] }); TestAssert.isTrue(result.sent); TestAssert.lengthOf(result.notifications_sent, 1); TestAssert.equal(result.notifications_sent[0], 'admin_notification'); }); suite.test('Send Notifications: Should handle multiple notification IDs', async () => { mockHttpClient.setMockResponse('POST', '/entries/100/notifications', new MockResponse({ notifications_sent: ['notification_1', 'notification_2', 'notification_3'] })); const result = await client.sendNotifications({ entry_id: 100, notification_ids: ['notification_1', 'notification_2', 'notification_3'] }); TestAssert.isTrue(result.sent); TestAssert.lengthOf(result.notifications_sent, 3); }); suite.test('Send Notifications: Should require entry_id', async () => { await TestAssert.throwsAsync( () => client.sendNotifications({}), 'entry_id', 'Should require entry_id' ); }); suite.test('Send Notifications: Should handle non-existent entry', async () => { mockHttpClient.setMockResponse('POST', '/entries/999/notifications', new MockResponse( { message: 'Entry not found' }, 404 )); await TestAssert.throwsAsync( () => client.sendNotifications({ entry_id: 999 }), 'not found', 'Should handle non-existent entry' ); }); // ================================= // EDGE CASES AND FAILURE MODES // ================================= suite.test('Edge Case: Should handle spam detection', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: false, validation_messages: { 'honeypot': 'Spam detected' }, is_spam: true })); const result = await client.submitFormData({ form_id: 1, input_1: 'Spam content', gf_honeypot: 'filled' // Honeypot field filled }); TestAssert.isFalse(result.success); TestAssert.includes(result.validation_messages.honeypot, 'Spam'); }); suite.test('Edge Case: Should handle CAPTCHA validation', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: false, validation_messages: { 'captcha': 'The reCAPTCHA was invalid' } })); const result = await client.submitFormData({ form_id: 1, input_1: 'John', 'g-recaptcha-response': 'invalid-token' }); TestAssert.isFalse(result.success); TestAssert.includes(result.validation_messages.captcha, 'reCAPTCHA'); }); suite.test('Edge Case: Should handle save and continue', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: true, resume_token: 'abc123def456', resume_url: 'https://example.com/form?gf_token=abc123def456', saved: true })); const result = await client.submitFormData({ form_id: 1, input_1: 'Partial data', save: true }); TestAssert.isTrue(result.success); TestAssert.equal(result.resume_token, 'abc123def456'); }); suite.test('Failure Mode: Should handle payment validation errors', async () => { mockHttpClient.setMockResponse('POST', '/forms/1/submissions', new MockResponse({ is_valid: false, validation_messages: { 'creditcard': 'Credit card number is invalid', 'payment': 'Payment failed: Card declined' } })); const result = await client.submitFormData({ form_id: 1, input_cc: '4111111111111111', input_cvv: '123' }); TestAssert.isFalse(result.success); TestAssert.includes(result.validation_messages.payment, 'declined'); }); suite.test('Failure Mode: Should handle notification sending failures', async () => { mockHttpClient.setMockResponse('POST', '/entries/100/notifications', new MockResponse( { message: 'Failed to send notifications', errors: ['SMTP connection failed'] }, 500 )); await TestAssert.throwsAsync( () => client.sendNotifications({ entry_id: 100 }), 'Server error', 'Should handle notification failures' ); }); suite.test('Failure Mode: Should handle form not found', async () => { mockHttpClient.setMockResponse('POST', '/forms/999/submissions', new MockResponse( { message: 'Form not found' }, 404 )); await TestAssert.throwsAsync( () => client.submitFormData({ form_id: 999, input_1: 'Test' }), 'not found', 'Should handle form not found' ); }); // Run tests suite.run().then(results => { process.exit(results.failed > 0 ? 1 : 0); }); export default suite;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/GravityKit/gravity-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server