UNPKG

@zeix/ui-element

Version:

UIElement - a HTML-first library for reactive Web Components

351 lines (279 loc) 10.3 kB
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Code Block Component Tests</title> </head> <body> <!-- Test fixtures --> <module-codeblock id="test1" collapsed copy-success="Copied!" copy-error="Error trying to copy to clipboard!" > <p class="meta"> <span class="file">test-file.js</span> <span class="language">javascript</span> </p> <pre><code class="language-javascript">console.log('Hello, World!');</code></pre> <basic-button class="copy"> <button type="button" class="secondary small"> <span class="label">Copy</span> </button> </basic-button> <button type="button" class="overlay">Expand</button> </module-codeblock> <module-codeblock id="test2" copy-success="Success!" copy-error="Failed!" > <p class="meta"> <span class="file">uncollapsed.js</span> <span class="language">javascript</span> </p> <pre><code class="language-javascript">const x = 42;</code></pre> <basic-button class="copy"> <button type="button" class="secondary small"> <span class="label">Copy Code</span> </button> </basic-button> <button type="button" class="overlay">Expand</button> </module-codeblock> <module-codeblock id="test3" collapsed> <p class="meta"> <span class="file">no-messages.js</span> <span class="language">javascript</span> </p> <pre><code class="language-javascript">// No success/error messages</code></pre> <basic-button class="copy"> <button type="button" class="secondary small"> <span class="label">Copy</span> </button> </basic-button> <button type="button" class="overlay">Expand</button> </module-codeblock> <module-codeblock id="test4"> <p class="meta"> <span class="file">empty.js</span> <span class="language">javascript</span> </p> <pre><code class="language-javascript"></code></pre> <basic-button class="copy"> <button type="button" class="secondary small"> <span class="label">Copy Empty</span> </button> </basic-button> <button type="button" class="overlay">Expand</button> </module-codeblock> <script type="module"> import { runTests } from '@web/test-runner-mocha' import { assert } from '@esm-bundle/chai' import '../../../docs/assets/main.js' // Built components bundle const wait = ms => new Promise(resolve => setTimeout(resolve, ms)) const animationFrame = () => new Promise(requestAnimationFrame) const microtask = () => new Promise(queueMicrotask) const tick = async () => { await animationFrame() // Wait for effects to execute await microtask() // Wait for DOM to reflect changes } // Mock clipboard API for testing let mockClipboard = { writeText: null, // Will be set per test lastWrittenText: '', shouldFail: false, } // Store original clipboard API const originalWriteText = navigator.clipboard?.writeText const setupClipboardMock = (shouldFail = false) => { mockClipboard.shouldFail = shouldFail mockClipboard.lastWrittenText = '' mockClipboard.writeText = async text => { if (mockClipboard.shouldFail) { throw new Error('Clipboard write failed') } mockClipboard.lastWrittenText = text return Promise.resolve() } // Replace the writeText method instead of the whole clipboard if (navigator.clipboard) { navigator.clipboard.writeText = mockClipboard.writeText } } const restoreClipboard = () => { if (navigator.clipboard && originalWriteText) { navigator.clipboard.writeText = originalWriteText } } runTests(() => { describe('Code Block Component', () => { afterEach(() => { restoreClipboard() }) it('should verify component exists and has expected structure', () => { const el = document.getElementById('test1') assert.isNotNull(el) assert.equal( el.tagName.toLowerCase(), 'module-codeblock', ) assert.isDefined(el.collapsed) assert.isBoolean(el.collapsed) }) it('should initialize with collapsed state from attribute', async () => { const el = document.getElementById('test1') assert.isTrue(el.collapsed) assert.isTrue(el.hasAttribute('collapsed')) }) it('should initialize without collapsed state when no attribute', async () => { const el = document.getElementById('test2') assert.isFalse(el.collapsed) assert.isFalse(el.hasAttribute('collapsed')) }) it('should expand when overlay is clicked', async () => { const el = document.getElementById('test1') const overlay = el.querySelector('.overlay') // Reset to collapsed state el.collapsed = true assert.isTrue(el.collapsed) assert.isTrue(el.hasAttribute('collapsed')) // Click overlay to expand overlay.click() assert.isFalse(el.collapsed) assert.isFalse(el.hasAttribute('collapsed')) }) it('should handle programmatic collapsed state changes', async () => { const el = document.getElementById('test2') // Set collapsed programmatically el.collapsed = true assert.isTrue(el.collapsed) assert.isTrue(el.hasAttribute('collapsed')) // Unset collapsed programmatically el.collapsed = false assert.isFalse(el.collapsed) assert.isFalse(el.hasAttribute('collapsed')) }) it('should copy code content to clipboard successfully', async () => { setupClipboardMock(false) const el = document.getElementById('test1') const copyButton = el.querySelector('.copy') const code = el.querySelector('code') copyButton.click() await wait(50) // Wait for async clipboard operation assert.equal( mockClipboard.lastWrittenText, code.textContent.trim(), ) }) it('should show success feedback and restore button state', async () => { setupClipboardMock(false) const el = document.getElementById('test1') const copyButton = el.querySelector('.copy') const originalLabel = copyButton.label || copyButton.textContent.trim() copyButton.click() await wait(50) // Wait for async clipboard operation // Check button is disabled and shows success message assert.isTrue(copyButton.disabled) assert.equal(copyButton.label, 'Copied!') // Wait for timeout to restore button (1000ms for success) await wait(1100) // Check button is restored assert.isFalse(copyButton.disabled) assert.equal(copyButton.label, originalLabel) }) /* it('should handle clipboard errors and show error feedback', async () => { setupClipboardMock(true) // Force clipboard to fail const el = document.getElementById('test1') const copyButton = el.querySelector('.copy') const originalLabel = copyButton.label || copyButton.textContent.trim() copyButton.click() await wait(50) // Wait for async clipboard operation // Check button is disabled and shows error message assert.isTrue(copyButton.disabled) assert.equal( copyButton.label, 'Error trying to copy to clipboard!', ) }) */ it('should use different success/error messages per component', async () => { setupClipboardMock(false) const el = document.getElementById('test2') const copyButton = el.querySelector('.copy') copyButton.click() await wait(50) // Wait for async clipboard operation assert.equal(copyButton.label, 'Success!') // Test error message too /* setupClipboardMock(true) await wait(1100) // Wait for button to restore copyButton.click() await wait(50) assert.equal(copyButton.label, 'Failed!') */ }) it('should fall back to original label when no success/error attributes', async () => { setupClipboardMock(false) const el = document.getElementById('test3') const copyButton = el.querySelector('.copy') const originalLabel = 'Copied!' // Hardcoded fallback in JS source copyButton.click() await wait(50) // Wait for async clipboard operation // Should show original label since no copy-success attribute assert.equal(copyButton.label, originalLabel) assert.isTrue(copyButton.disabled) }) it('should handle empty code content', async () => { setupClipboardMock(false) const el = document.getElementById('test4') const copyButton = el.querySelector('.copy') const code = el.querySelector('code') copyButton.click() await wait(50) // Wait for async clipboard operation assert.equal(mockClipboard.lastWrittenText, '') }) it('should maintain proper collapsed attribute binding', async () => { const el = document.getElementById('test3') // Test that attribute and property stay in sync el.collapsed = true assert.isTrue(el.hasAttribute('collapsed')) el.collapsed = false assert.isFalse(el.hasAttribute('collapsed')) // Test setting attribute el.setAttribute('collapsed', '') assert.isTrue(el.collapsed) el.removeAttribute('collapsed') assert.isFalse(el.collapsed) }) it('should preserve collapsed property type', () => { const el = document.getElementById('test1') assert.isBoolean(el.collapsed) el.collapsed = true assert.isBoolean(el.collapsed) assert.isTrue(el.collapsed) el.collapsed = false assert.isBoolean(el.collapsed) assert.isFalse(el.collapsed) }) it('should handle rapid copy button clicks', async () => { setupClipboardMock(false) const el = document.getElementById('test2') const copyButton = el.querySelector('.copy') // Click rapidly multiple times copyButton.click() copyButton.click() copyButton.click() await wait(50) // Button should be disabled after first click assert.isTrue(copyButton.disabled) // Only one copy operation should have occurred assert.equal( mockClipboard.lastWrittenText, 'const x = 42;', ) }) }) }) </script> </body> </html>