app/tests/e2e/conflict-resolution-edge-cases.spec.ts

362 lines
No EOL
17 KiB
TypeScript

import { test, expect } from '@playwright/test'
import { ConflictResolutionFormHelper, MarkdownValidator } from './conflict-resolution-utils'
test.describe('Conflict Resolution Framework - Edge Cases and Error Handling', () => {
test('Handle special characters in organization name', async ({ page }) => {
const formHelper = new ConflictResolutionFormHelper(page)
await formHelper.goto()
const specialCharNames = [
'O\'Reilly & Associates',
'Smith-Johnson Collective',
'Café Workers Co-op',
'Future.is.Now LLC',
'Workers! United?'
]
for (const orgName of specialCharNames) {
await test.step(`Test organization name: ${orgName}`, async () => {
await page.fill('input[placeholder*="organization name"]', orgName)
const orgTypeButton = page.locator('button:has-text("Select organization type"), [role="combobox"]:has-text("Select organization type")').first()
await orgTypeButton.click()
await page.locator('text="Worker Cooperative"').click()
await page.fill('input[type="number"]', '5')
await page.locator('label:has-text("Financial disagreements") input[type="checkbox"]').check()
const markdown = await formHelper.downloadMarkdown()
// Should contain the exact organization name
expect(markdown).toContain(orgName)
// Should handle possessive correctly
const expectedPossessive = orgName.endsWith('s') ? orgName + "'" : orgName + "'s"
expect(markdown).toContain(expectedPossessive)
// Check filename sanitization would work
const expectedFilename = `${orgName.replace(/[^a-zA-Z0-9]/g, "_")}_conflict_resolution_policy.md`
expect(expectedFilename).not.toContain('[')
expect(expectedFilename).not.toContain('?')
})
}
})
test('Handle very long text inputs', async ({ page }) => {
const formHelper = new ConflictResolutionFormHelper(page)
await formHelper.goto()
// Fill basic info
await page.fill('input[placeholder*="organization name"]', 'Long Text Test Org')
const orgTypeButton = page.locator('button:has-text("Select organization type"), [role="combobox"]:has-text("Select organization type")').first()
await orgTypeButton.click()
await page.locator('text="Nonprofit Organization"').click()
await page.fill('input[type="number"]', '10')
await page.locator('label:has-text("Financial disagreements") input[type="checkbox"]').check()
// Test very long custom values
const longCustomValues = 'We believe in sustainable practices, environmental stewardship, social justice, economic equality, democratic governance, transparent decision-making, inclusive participation, community empowerment, cooperative principles, mutual aid, solidarity economics, regenerative systems, anti-oppression work, decolonization efforts, intersectional feminism, racial equity, and transformative justice as core elements of our organizational culture and operational framework.'
const longReflectionPrompts = 'Consider the following comprehensive questions during your reflection period: What personal biases might be influencing your perception of this situation? How can you approach this conflict with curiosity rather than judgment? What would healing look like for all parties involved? How can this situation become an opportunity for deeper understanding and stronger relationships? What systemic factors might be contributing to this conflict? How can we address root causes rather than just symptoms? What would your most compassionate self do in this situation?'
const longResources = 'Community Mediation Center of Greater Metropolitan Area: (555) 123-4567, available Monday-Friday 9am-5pm, specializing in workplace conflicts, restorative justice practices, and community healing circles. Legal Aid Society Cooperative Division: www.legal-aid-coops.org, providing free and low-cost legal services to cooperatives, worker-owned businesses, and community organizations. Conflict Transformation Institute: offering workshops, training, and certification programs in nonviolent communication, restorative justice, and conflict transformation methodologies.'
// Fill long text fields
await page.fill('textarea[placeholder*="values"]', longCustomValues)
await page.fill('textarea[placeholder*="reflection"]', longReflectionPrompts)
await page.fill('textarea[placeholder*="resources"]', longResources)
// Generate markdown
const markdown = await formHelper.downloadMarkdown()
// Verify all long texts are preserved
expect(markdown).toContain(longCustomValues)
expect(markdown).toContain(longReflectionPrompts)
expect(markdown).toContain(longResources)
// Check that text wasn't truncated (should contain end portions)
expect(markdown).toContain('operational framework')
expect(markdown).toContain('compassionate self do')
expect(markdown).toContain('transformation methodologies')
})
test('Handle empty and minimal form configurations', async ({ page }) => {
const formHelper = new ConflictResolutionFormHelper(page)
await formHelper.goto()
// Fill absolute minimum required fields only
await page.fill('input[placeholder*="organization name"]', 'Minimal Org')
const orgTypeButton = page.locator('button:has-text("Select organization type"), [role="combobox"]:has-text("Select organization type")').first()
await orgTypeButton.click()
await page.locator('text="Social Enterprise"').click()
await page.fill('input[type="number"]', '2')
// Select minimum required checkboxes (one conflict type)
await page.locator('label:has-text("Financial disagreements") input[type="checkbox"]').check()
// Leave all optional fields empty
// Validate form
await page.locator('button:has-text("CHECK")').click()
await expect(page.locator('text=Form is complete')).toBeVisible()
// Generate markdown
const markdown = await formHelper.downloadMarkdown()
// Should still generate valid document
expect(markdown).toContain('# Minimal Org Conflict Resolution Policy')
expect(markdown).toContain('## Purpose')
expect(markdown).toContain('Financial disagreements')
// Should handle empty sections gracefully
expect(markdown).not.toContain('[None specified]')
expect(markdown).not.toContain('[Not specified]')
expect(markdown).not.toContain('undefined')
expect(markdown).not.toContain('null')
})
test('Validate form state persistence across page reloads', async ({ page }) => {
const formHelper = new ConflictResolutionFormHelper(page)
await formHelper.goto()
// Fill some form data
await page.fill('input[placeholder*="organization name"]', 'Persistence Test Org')
const orgTypeButton = page.locator('button:has-text("Select organization type"), [role="combobox"]:has-text("Select organization type")').first()
await orgTypeButton.click()
await page.locator('text="Consumer Cooperative"').click()
await page.fill('input[type="number"]', '15')
await page.locator('label:has-text("Mutual Care") input[type="checkbox"]').check()
await page.locator('label:has-text("Code of Conduct violations") input[type="checkbox"]').check()
await page.fill('textarea[placeholder*="values"]', 'Test custom values content')
// Wait for auto-save
await page.waitForTimeout(1000)
// Reload page
await page.reload()
await page.waitForLoadState('networkidle')
// Check that form data persisted
await expect(page.locator('input[placeholder*="organization name"]')).toHaveValue('Persistence Test Org')
await expect(page.locator('select[placeholder*="organization type"]')).toHaveValue('Consumer Cooperative')
await expect(page.locator('input[type="number"]')).toHaveValue('15')
await expect(page.locator('label:has-text("Mutual Care") input[type="checkbox"]')).toBeChecked()
await expect(page.locator('label:has-text("Code of Conduct violations") input[type="checkbox"]')).toBeChecked()
await expect(page.locator('textarea[placeholder*="values"]')).toHaveValue('Test custom values content')
// Generate markdown and verify persisted data appears
const markdown = await formHelper.downloadMarkdown()
expect(markdown).toContain('Persistence Test Org')
expect(markdown).toContain('Consumer Cooperative')
expect(markdown).toContain('Mutual Care')
expect(markdown).toContain('Code of Conduct violations')
expect(markdown).toContain('Test custom values content')
})
test('Handle rapid form interactions and auto-save', async ({ page }) => {
const formHelper = new ConflictResolutionFormHelper(page)
await formHelper.goto()
// Rapidly fill multiple fields
await page.fill('input[placeholder*="organization name"]', 'Rapid Test Org')
const orgTypeButton2 = page.locator('button:has-text("Select organization type"), [role="combobox"]:has-text("Select organization type")').first()
await orgTypeButton2.click()
await page.locator('text="Worker Cooperative"').click()
await page.fill('input[type="number"]', '8')
// Rapidly check/uncheck multiple checkboxes
const checkboxes = [
'Mutual Care',
'Transparency',
'Accountability',
'Code of Conduct violations',
'Financial disagreements',
'Conflicts of interest'
]
for (const checkbox of checkboxes) {
await page.locator(`label:has-text("${checkbox}") input[type="checkbox"]`).check()
await page.waitForTimeout(100) // Small delay to simulate real user interaction
}
// Rapidly change dropdown values
await page.selectOption('select[placeholder*="response"]', 'Within 24 hours')
await page.selectOption('select[placeholder*="target"]', '1 week')
await page.selectOption('select[placeholder*="schedule"]', 'Every 6 months')
// Wait for auto-save to complete
await page.waitForTimeout(2000)
// Generate markdown
const markdown = await formHelper.downloadMarkdown()
// Verify all rapid changes were captured
expect(markdown).toContain('Rapid Test Org')
expect(markdown).toContain('Worker Cooperative')
for (const checkbox of checkboxes) {
expect(markdown).toContain(checkbox)
}
expect(markdown).toContain('24 hours')
expect(markdown).toContain('1 week')
expect(markdown).toContain('every 6 months')
})
test('Validate preview functionality matches download', async ({ page }) => {
const formHelper = new ConflictResolutionFormHelper(page)
await formHelper.goto()
// Fill form with comprehensive data
await page.fill('input[placeholder*="organization name"]', 'Preview Test Org')
const orgTypeButton2 = page.locator('button:has-text("Select organization type"), [role="combobox"]:has-text("Select organization type")').first()
await orgTypeButton2.click()
await page.locator('text="Worker Cooperative"').click()
await page.fill('input[type="number"]', '7')
await page.locator('label:has-text("Mutual Care") input[type="checkbox"]').check()
await page.locator('label:has-text("Financial disagreements") input[type="checkbox"]').check()
await page.fill('textarea[placeholder*="values"]', 'Preview test custom values')
// Show preview
await page.locator('button:has-text("Show Preview")').click()
await expect(page.locator('.policy-preview')).toBeVisible()
// Get preview content
const previewContent = await page.locator('.policy-preview').textContent()
// Hide preview and download markdown
await page.locator('button:has-text("Hide Preview")').click()
const markdownContent = await formHelper.downloadMarkdown()
// Preview and markdown should contain the same core information
// (Note: formatting will differ between HTML and Markdown)
expect(previewContent).toContain('Preview Test Org')
expect(markdownContent).toContain('Preview Test Org')
expect(previewContent).toContain('Mutual Care')
expect(markdownContent).toContain('Mutual Care')
expect(previewContent).toContain('Financial disagreements')
expect(markdownContent).toContain('Financial disagreements')
expect(previewContent).toContain('Preview test custom values')
expect(markdownContent).toContain('Preview test custom values')
})
test('Handle browser compatibility and JavaScript errors', async ({ page }) => {
const formHelper = new ConflictResolutionFormHelper(page)
// Listen for console errors
const consoleErrors: string[] = []
page.on('console', msg => {
if (msg.type() === 'error') {
consoleErrors.push(msg.text())
}
})
// Listen for page errors
const pageErrors: string[] = []
page.on('pageerror', error => {
pageErrors.push(error.message)
})
await formHelper.goto()
// Perform standard form operations
await page.fill('input[placeholder*="organization name"]', 'Error Test Org')
const orgTypeButton = page.locator('button:has-text("Select organization type"), [role="combobox"]:has-text("Select organization type")').first()
await orgTypeButton.click()
await page.locator('text="Nonprofit Organization"').click()
await page.fill('input[type="number"]', '5')
await page.locator('label:has-text("Financial disagreements") input[type="checkbox"]').check()
// Try to generate markdown
const markdown = await formHelper.downloadMarkdown()
// Should generate valid content despite any minor errors
expect(markdown).toContain('Error Test Org')
// Check for critical JavaScript errors (some console warnings are acceptable)
const criticalErrors = pageErrors.filter(error =>
!error.includes('warning') &&
!error.includes('deprecated') &&
!error.includes('favicon')
)
expect(criticalErrors).toEqual([])
})
test('Validate accessibility and keyboard navigation', async ({ page }) => {
const formHelper = new ConflictResolutionFormHelper(page)
await formHelper.goto()
// Test basic keyboard navigation
await page.keyboard.press('Tab') // Should focus first input
await page.keyboard.type('Accessibility Test Org')
await page.keyboard.press('Tab') // Should focus org type dropdown
await page.keyboard.press('Space') // Open dropdown
await page.keyboard.press('ArrowDown') // Select option
await page.keyboard.press('Enter') // Confirm selection
await page.keyboard.press('Tab') // Should focus member count
await page.keyboard.type('6')
// Navigate to a checkbox and check it via keyboard
await page.locator('label:has-text("Financial disagreements") input[type="checkbox"]').focus()
await page.keyboard.press('Space') // Check the checkbox
// Verify the form can be submitted via keyboard
await page.locator('button:has-text("CHECK")').focus()
await page.keyboard.press('Enter')
await expect(page.locator('text=Form is complete')).toBeVisible()
// Generate markdown to verify keyboard input worked
const markdown = await formHelper.downloadMarkdown()
expect(markdown).toContain('Accessibility Test Org')
expect(markdown).toContain('Financial disagreements')
})
test('Performance test with large form data', async ({ page }) => {
const formHelper = new ConflictResolutionFormHelper(page)
await formHelper.goto()
const startTime = Date.now()
// Fill comprehensive form data
await page.fill('input[placeholder*="organization name"]', 'Performance Test Organization with Very Long Name')
const orgTypeButton2 = page.locator('button:has-text("Select organization type"), [role="combobox"]:has-text("Select organization type")').first()
await orgTypeButton2.click()
await page.locator('text="Worker Cooperative"').click()
await page.fill('input[type="number"]', '250')
// Check many checkboxes across all sections
const allCheckboxes = await page.locator('input[type="checkbox"]').all()
for (let i = 0; i < Math.min(allCheckboxes.length, 20); i++) {
await allCheckboxes[i].check()
}
// Fill large text areas
const largeText = 'This is a very long text that simulates a comprehensive organizational policy with detailed explanations, extensive procedures, multiple stakeholders, complex workflows, and thorough documentation requirements. '.repeat(50)
const textareas = await page.locator('textarea').all()
for (const textarea of textareas) {
await textarea.fill(largeText.substring(0, 1000)) // Limit to reasonable size
}
const fillTime = Date.now() - startTime
// Generate markdown
const markdownStartTime = Date.now()
const markdown = await formHelper.downloadMarkdown()
const markdownTime = Date.now() - markdownStartTime
// Verify content was generated correctly
expect(markdown).toContain('Performance Test Organization')
expect(markdown.length).toBeGreaterThan(5000) // Should be substantial
// Performance assertions (adjust thresholds as needed)
expect(fillTime).toBeLessThan(30000) // Should fill form in under 30 seconds
expect(markdownTime).toBeLessThan(10000) // Should generate markdown in under 10 seconds
console.log(`Form fill time: ${fillTime}ms, Markdown generation time: ${markdownTime}ms`)
})
})