chore: update application configuration and UI components for improved styling and functionality
This commit is contained in:
parent
0af6b17792
commit
37ab8d7bab
54 changed files with 23293 additions and 1666 deletions
362
tests/e2e/conflict-resolution-edge-cases.spec.ts
Normal file
362
tests/e2e/conflict-resolution-edge-cases.spec.ts
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
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`)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue