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
330
tests/e2e/conflict-resolution-parity.spec.ts
Normal file
330
tests/e2e/conflict-resolution-parity.spec.ts
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
import { testFormData, ConflictResolutionFormHelper, MarkdownValidator } from './conflict-resolution-utils'
|
||||
|
||||
test.describe('Conflict Resolution Framework - Form to Markdown Parity', () => {
|
||||
|
||||
test('Complete form fill and validate 100% parity with markdown output', async ({ page }) => {
|
||||
const formHelper = new ConflictResolutionFormHelper(page)
|
||||
|
||||
// Navigate to the form
|
||||
await formHelper.goto()
|
||||
await expect(page.locator('h1:has-text("CONFLICT RESOLUTION FRAMEWORK")').first()).toBeVisible()
|
||||
|
||||
// Fill all form sections systematically
|
||||
await test.step('Fill basic organization information', async () => {
|
||||
await formHelper.fillBasicInfo(testFormData)
|
||||
})
|
||||
|
||||
await test.step('Fill core values section', async () => {
|
||||
await formHelper.fillCoreValues(testFormData)
|
||||
})
|
||||
|
||||
await test.step('Fill conflict types section', async () => {
|
||||
await formHelper.fillConflictTypes(testFormData)
|
||||
})
|
||||
|
||||
await test.step('Fill resolution approach section', async () => {
|
||||
await formHelper.fillApproach(testFormData)
|
||||
})
|
||||
|
||||
await test.step('Fill report receivers section', async () => {
|
||||
await formHelper.fillReportReceivers(testFormData)
|
||||
})
|
||||
|
||||
await test.step('Fill mediator structure section', async () => {
|
||||
await formHelper.fillMediatorStructure(testFormData)
|
||||
})
|
||||
|
||||
await test.step('Fill process steps section', async () => {
|
||||
await formHelper.fillProcessSteps(testFormData)
|
||||
})
|
||||
|
||||
await test.step('Fill timeline section', async () => {
|
||||
await formHelper.fillTimeline(testFormData)
|
||||
})
|
||||
|
||||
await test.step('Fill available actions section', async () => {
|
||||
await formHelper.fillAvailableActions(testFormData)
|
||||
})
|
||||
|
||||
await test.step('Fill documentation section', async () => {
|
||||
await formHelper.fillDocumentation(testFormData)
|
||||
})
|
||||
|
||||
await test.step('Fill implementation section', async () => {
|
||||
await formHelper.fillImplementation(testFormData)
|
||||
})
|
||||
|
||||
await test.step('Fill enhanced sections', async () => {
|
||||
await formHelper.fillEnhancedSections(testFormData)
|
||||
})
|
||||
|
||||
// Wait for auto-save to complete
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
// Validate form completion
|
||||
await test.step('Validate form completion', async () => {
|
||||
await page.locator('button:has-text("CHECK")').click()
|
||||
// Should see success message
|
||||
await expect(page.locator('text=Form is complete')).toBeVisible({ timeout: 5000 })
|
||||
})
|
||||
|
||||
// Generate and download markdown
|
||||
const markdownContent = await test.step('Download markdown', async () => {
|
||||
return await formHelper.downloadMarkdown()
|
||||
})
|
||||
|
||||
// Validate markdown content against form data
|
||||
await test.step('Validate markdown parity', async () => {
|
||||
const validator = new MarkdownValidator(markdownContent)
|
||||
const errors = validator.validateAll(testFormData)
|
||||
|
||||
if (errors.length > 0) {
|
||||
console.log('Markdown content:', markdownContent.substring(0, 1000) + '...')
|
||||
console.log('Validation errors:', errors)
|
||||
}
|
||||
|
||||
expect(errors).toEqual([])
|
||||
})
|
||||
|
||||
// Additional specific validations
|
||||
await test.step('Validate document structure', async () => {
|
||||
expect(markdownContent).toContain('# Test Cooperative Solutions Conflict Resolution Policy')
|
||||
expect(markdownContent).toContain('## Purpose')
|
||||
expect(markdownContent).toContain('## Who does this policy apply to?')
|
||||
expect(markdownContent).toContain('## What policy should be used?')
|
||||
expect(markdownContent).toContain('## Guiding principles')
|
||||
expect(markdownContent).toContain('## Definitions')
|
||||
expect(markdownContent).toContain('## Responsibility for implementation')
|
||||
expect(markdownContent).toContain('## Procedures')
|
||||
expect(markdownContent).toContain('### Reflection')
|
||||
expect(markdownContent).toContain('## Direct Resolution')
|
||||
expect(markdownContent).toContain('## Assisted Resolution')
|
||||
expect(markdownContent).toContain('### Formal Complaints')
|
||||
expect(markdownContent).toContain('## Other Redress')
|
||||
expect(markdownContent).toContain('## Acknowledgments')
|
||||
})
|
||||
|
||||
await test.step('Validate data integrity', async () => {
|
||||
// Check that no placeholder text remains
|
||||
expect(markdownContent).not.toContain('[Organization Name]')
|
||||
expect(markdownContent).not.toContain('[Date]')
|
||||
expect(markdownContent).not.toContain('[Not specified]')
|
||||
expect(markdownContent).not.toContain('[None selected]')
|
||||
|
||||
// Check proper possessive forms
|
||||
expect(markdownContent).toContain("Test Cooperative Solutions'")
|
||||
expect(markdownContent).not.toContain("Test Cooperative Solutions's")
|
||||
|
||||
// Check no redundant text
|
||||
expect(markdownContent).not.toContain('within within')
|
||||
expect(markdownContent).not.toContain('members members')
|
||||
})
|
||||
})
|
||||
|
||||
test('Validate organization type variations', async ({ page }) => {
|
||||
const formHelper = new ConflictResolutionFormHelper(page)
|
||||
|
||||
for (const orgType of ['Worker Cooperative', 'Consumer Cooperative', 'Nonprofit Organization', 'Social Enterprise']) {
|
||||
await test.step(`Test organization type: ${orgType}`, async () => {
|
||||
await formHelper.goto()
|
||||
|
||||
// Fill minimal data with specific org type
|
||||
await page.fill('input[placeholder*="organization name"]', `Test ${orgType}`)
|
||||
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="${orgType}"`).click()
|
||||
await page.fill('input[type="number"]', '5')
|
||||
|
||||
// Select one conflict type to make form valid
|
||||
await page.locator('label:has-text("Financial disagreements") input[type="checkbox"]').check()
|
||||
|
||||
// Check validation
|
||||
await page.locator('button:has-text("CHECK")').click()
|
||||
await expect(page.locator('text=Form is complete')).toBeVisible({ timeout: 5000 })
|
||||
|
||||
// Download and validate
|
||||
const markdown = await formHelper.downloadMarkdown()
|
||||
|
||||
// Validate org type specific content
|
||||
if (orgType.includes('Cooperative')) {
|
||||
expect(markdown).toContain('members')
|
||||
expect(markdown).toContain('Directors, staff, members')
|
||||
} else {
|
||||
expect(markdown).toContain('community members')
|
||||
expect(markdown).toContain('Directors, staff, community members')
|
||||
}
|
||||
|
||||
// Check possessive handling
|
||||
expect(markdown).toContain(`Test ${orgType}`)
|
||||
expect(markdown).not.toContain(`Test ${orgType}'s's`)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('Validate checkbox selections integrity', async ({ page }) => {
|
||||
const formHelper = new ConflictResolutionFormHelper(page)
|
||||
await formHelper.goto()
|
||||
|
||||
// Fill basic info
|
||||
await page.fill('input[placeholder*="organization name"]', 'Checkbox 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="Worker Cooperative"').click()
|
||||
await page.fill('input[type="number"]', '8')
|
||||
|
||||
// Test specific checkbox combinations
|
||||
const checkboxTests = [
|
||||
{
|
||||
section: 'Core Values',
|
||||
items: ['Mutual Care', 'Anti-Oppression', 'Collective Liberation'],
|
||||
shouldFind: ['Mutual Care', 'Anti-Oppression', 'Collective Liberation']
|
||||
},
|
||||
{
|
||||
section: 'Conflict Types',
|
||||
items: ['Code of Conduct violations', 'Harassment or discrimination', 'Conflicts of interest'],
|
||||
shouldFind: ['Code of Conduct violations', 'Harassment or discrimination', 'Conflicts of interest']
|
||||
},
|
||||
{
|
||||
section: 'Available Actions',
|
||||
items: ['Verbal warning', 'Mediation facilitation', 'Removal from organization'],
|
||||
shouldFind: ['Verbal warning', 'Mediation facilitation', 'Removal from organization']
|
||||
}
|
||||
]
|
||||
|
||||
for (const test of checkboxTests) {
|
||||
await test.step(`Test ${test.section} checkboxes`, async () => {
|
||||
// Clear any existing selections first
|
||||
for (const item of test.items) {
|
||||
const checkbox = page.locator(`label:has-text("${item}") input[type="checkbox"]`)
|
||||
if (await checkbox.isChecked()) {
|
||||
await checkbox.uncheck()
|
||||
}
|
||||
}
|
||||
|
||||
// Select specific items
|
||||
for (const item of test.items) {
|
||||
await page.locator(`label:has-text("${item}") input[type="checkbox"]`).check()
|
||||
}
|
||||
|
||||
// Download markdown
|
||||
const markdown = await formHelper.downloadMarkdown()
|
||||
|
||||
// Validate each selected item appears
|
||||
for (const expectedItem of test.shouldFind) {
|
||||
expect(markdown).toContain(expectedItem)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('Validate toggle sections functionality', async ({ page }) => {
|
||||
const formHelper = new ConflictResolutionFormHelper(page)
|
||||
await formHelper.goto()
|
||||
|
||||
// Fill basic required fields
|
||||
await page.fill('input[placeholder*="organization name"]', 'Toggle 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"]', '6')
|
||||
await page.locator('label:has-text("Financial disagreements") input[type="checkbox"]').check()
|
||||
|
||||
// Test toggleable sections
|
||||
const toggleSections = [
|
||||
{ name: 'Reflection', content: 'reflection process' },
|
||||
{ name: 'Direct Resolution', content: 'escalate the bandwidth' },
|
||||
{ name: 'External Resources', content: 'Human Rights Commission' }
|
||||
]
|
||||
|
||||
for (const section of toggleSections) {
|
||||
await test.step(`Test ${section.name} section toggle`, async () => {
|
||||
// Find and enable toggle
|
||||
const toggle = page.locator(`.toggle:near(:text("${section.name}"))`).first()
|
||||
if (await toggle.isVisible()) {
|
||||
await toggle.click()
|
||||
await page.waitForTimeout(500) // Wait for UI update
|
||||
}
|
||||
|
||||
// Download markdown
|
||||
const markdown = await formHelper.downloadMarkdown()
|
||||
|
||||
// Section should be included when toggled on
|
||||
expect(markdown.toLowerCase()).toContain(section.content.toLowerCase())
|
||||
|
||||
// Toggle off and test again
|
||||
if (await toggle.isVisible()) {
|
||||
await toggle.click()
|
||||
await page.waitForTimeout(500)
|
||||
}
|
||||
|
||||
const markdownOff = await formHelper.downloadMarkdown()
|
||||
|
||||
// For some sections, content might still appear in different contexts
|
||||
// So we check for section-specific markers
|
||||
if (section.name === 'Reflection') {
|
||||
expect(markdownOff).not.toContain('### Reflection')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('Validate form validation prevents incomplete exports', async ({ page }) => {
|
||||
const formHelper = new ConflictResolutionFormHelper(page)
|
||||
await formHelper.goto()
|
||||
|
||||
// Test with minimal/incomplete data
|
||||
await page.fill('input[placeholder*="organization name"]', 'Incomplete Org')
|
||||
// Deliberately don't fill other required fields
|
||||
|
||||
// Try validation
|
||||
await page.locator('button:has-text("CHECK")').click()
|
||||
|
||||
// Should see error message
|
||||
await expect(page.locator(':has-text("complete")', { timeout: 5000 })).toBeVisible()
|
||||
await expect(page.locator(':has-text("required")')).toBeVisible()
|
||||
|
||||
// Now complete required fields
|
||||
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"]', '3')
|
||||
await page.locator('label:has-text("Financial disagreements") input[type="checkbox"]').check()
|
||||
|
||||
// Try validation again
|
||||
await page.locator('button:has-text("CHECK")').click()
|
||||
await expect(page.locator('text=Form is complete')).toBeVisible({ timeout: 5000 })
|
||||
})
|
||||
|
||||
test('Validate date handling and formatting', async ({ page }) => {
|
||||
const formHelper = new ConflictResolutionFormHelper(page)
|
||||
await formHelper.goto()
|
||||
|
||||
// Fill basic info
|
||||
await page.fill('input[placeholder*="organization name"]', 'Date 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="Worker Cooperative"').click()
|
||||
await page.fill('input[type="number"]', '4')
|
||||
await page.locator('label:has-text("Financial disagreements") input[type="checkbox"]').check()
|
||||
|
||||
// Fill specific dates
|
||||
const testDates = {
|
||||
created: '2024-01-15',
|
||||
review: '2025-01-15'
|
||||
}
|
||||
|
||||
await page.fill('input[type="date"]:first-of-type', testDates.created)
|
||||
await page.fill('input[type="date"]:last-of-type', testDates.review)
|
||||
|
||||
// Download and validate
|
||||
const markdown = await formHelper.downloadMarkdown()
|
||||
|
||||
expect(markdown).toContain(testDates.created)
|
||||
expect(markdown).toContain(testDates.review)
|
||||
|
||||
// Check proper date formatting in context
|
||||
expect(markdown).toContain(`*This policy was created on ${testDates.created}`)
|
||||
expect(markdown).toContain(`*Next review date: ${testDates.review}*`)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue