@coherent.js/testing 1.0.0-beta.6 → 1.0.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js.map +7 -0
- package/dist/matchers.js +246 -0
- package/dist/matchers.js.map +7 -0
- package/dist/test-renderer.js +254 -0
- package/dist/test-renderer.js.map +7 -0
- package/dist/test-utils.js +262 -0
- package/dist/test-utils.js.map +7 -0
- package/package.json +10 -2
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/test-renderer.js", "../src/test-utils.js", "../src/matchers.js", "../src/index.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * Coherent.js Test Renderer\n * \n * Provides utilities for rendering and testing Coherent.js components\n * in a test environment.\n * \n * @module testing/test-renderer\n */\n\nimport { render } from '@coherent.js/core';\n\n/**\n * Test renderer result\n * Provides methods to query and interact with rendered components\n */\nexport class TestRendererResult {\n constructor(component, html, container = null) {\n this.component = component;\n this.html = html;\n this.container = container;\n this.queries = new Map();\n }\n\n /**\n * Get element by test ID\n * @param {string} testId - Test ID to search for\n * @returns {Object|null} Element or null\n */\n getByTestId(testId) {\n const regex = new RegExp(`data-testid=\"${testId}\"[^>]*>([^<]*)<`, 'i');\n const match = this.html.match(regex);\n \n if (!match) {\n throw new Error(`Unable to find element with testId: ${testId}`);\n }\n \n return {\n text: match[1],\n html: match[0],\n testId,\n exists: true\n };\n }\n\n /**\n * Query element by test ID (returns null if not found)\n * @param {string} testId - Test ID to search for\n * @returns {Object|null} Element or null\n */\n queryByTestId(testId) {\n try {\n return this.getByTestId(testId);\n } catch {\n return null;\n }\n }\n\n /**\n * Get element by text content\n * @param {string|RegExp} text - Text to search for\n * @returns {Object} Element\n */\n getByText(text) {\n const regex = typeof text === 'string' \n ? new RegExp(`>([^<]*${text}[^<]*)<`, 'i')\n : new RegExp(`>([^<]*)<`, 'i');\n \n const match = this.html.match(regex);\n \n if (!match || (typeof text === 'string' && !match[1].includes(text))) {\n throw new Error(`Unable to find element with text: ${text}`);\n }\n \n return {\n text: match[1],\n html: match[0],\n exists: true\n };\n }\n\n /**\n * Query element by text (returns null if not found)\n * @param {string|RegExp} text - Text to search for\n * @returns {Object|null} Element or null\n */\n queryByText(text) {\n try {\n return this.getByText(text);\n } catch {\n return null;\n }\n }\n\n /**\n * Get element by class name\n * @param {string} className - Class name to search for\n * @returns {Object} Element\n */\n getByClassName(className) {\n const regex = new RegExp(`class=\"[^\"]*${className}[^\"]*\"[^>]*>([^<]*)<`, 'i');\n const match = this.html.match(regex);\n \n if (!match) {\n throw new Error(`Unable to find element with className: ${className}`);\n }\n \n return {\n text: match[1],\n html: match[0],\n className,\n exists: true\n };\n }\n\n /**\n * Query element by class name (returns null if not found)\n * @param {string} className - Class name to search for\n * @returns {Object|null} Element or null\n */\n queryByClassName(className) {\n try {\n return this.getByClassName(className);\n } catch {\n return null;\n }\n }\n\n /**\n * Get all elements by tag name\n * @param {string} tagName - Tag name to search for\n * @returns {Array<Object>} Array of elements\n */\n getAllByTagName(tagName) {\n const regex = new RegExp(`<${tagName}[^>]*>([^<]*)</${tagName}>`, 'gi');\n const matches = [...this.html.matchAll(regex)];\n \n return matches.map(match => ({\n text: match[1],\n html: match[0],\n tagName,\n exists: true\n }));\n }\n\n /**\n * Check if element exists\n * @param {string} selector - Selector (testId, text, className)\n * @param {string} type - Type of selector ('testId', 'text', 'className')\n * @returns {boolean} True if exists\n */\n exists(selector, type = 'testId') {\n switch (type) {\n case 'testId':\n return this.queryByTestId(selector) !== null;\n case 'text':\n return this.queryByText(selector) !== null;\n case 'className':\n return this.queryByClassName(selector) !== null;\n default:\n return false;\n }\n }\n\n /**\n * Get the rendered HTML\n * @returns {string} HTML string\n */\n getHTML() {\n return this.html;\n }\n\n /**\n * Get the component\n * @returns {Object} Component object\n */\n getComponent() {\n return this.component;\n }\n\n /**\n * Create a snapshot of the rendered output\n * @returns {string} Formatted HTML for snapshot testing\n */\n toSnapshot() {\n return this.html\n .replace(/>\\s+</g, '><') // Remove whitespace between tags\n .trim();\n }\n\n /**\n * Debug: print the rendered HTML\n */\n debug() {\n console.log('=== Rendered HTML ===');\n console.log(this.html);\n console.log('=== Component ===');\n console.log(JSON.stringify(this.component, null, 2));\n }\n}\n\n/**\n * Render a component for testing\n * \n * @param {Object} component - Component to render\n * @param {Object} [options] - Render options\n * @returns {TestRendererResult} Test renderer result\n * \n * @example\n * const { getByTestId } = renderComponent({\n * div: {\n * 'data-testid': 'my-div',\n * text: 'Hello World'\n * }\n * });\n * \n * expect(getByTestId('my-div').text).toBe('Hello World');\n */\nexport function renderComponent(component, options = {}) {\n const html = render(component, options);\n return new TestRendererResult(component, html);\n}\n\n/**\n * Render a component asynchronously\n * \n * @param {Object|Function} component - Component or component factory\n * @param {Object} [props] - Component props\n * @param {Object} [options] - Render options\n * @returns {Promise<TestRendererResult>} Test renderer result\n */\nexport async function renderComponentAsync(component, props = {}, options = {}) {\n // If component is a function, call it with props\n const resolvedComponent = typeof component === 'function' \n ? await component(props)\n : component;\n \n const html = render(resolvedComponent, options);\n return new TestRendererResult(resolvedComponent, html);\n}\n\n/**\n * Create a test renderer instance\n * Useful for testing component updates\n */\nexport class TestRenderer {\n constructor(component, options = {}) {\n this.component = component;\n this.options = options;\n this.result = null;\n this.renderCount = 0;\n }\n\n /**\n * Render the component\n * @returns {TestRendererResult} Render result\n */\n render() {\n this.renderCount++;\n const html = render(this.component, this.options);\n this.result = new TestRendererResult(this.component, html);\n return this.result;\n }\n\n /**\n * Update the component and re-render\n * @param {Object} newComponent - Updated component\n * @returns {TestRendererResult} Render result\n */\n update(newComponent) {\n this.component = newComponent;\n return this.render();\n }\n\n /**\n * Get the current result\n * @returns {TestRendererResult|null} Current result\n */\n getResult() {\n return this.result;\n }\n\n /**\n * Get render count\n * @returns {number} Number of renders\n */\n getRenderCount() {\n return this.renderCount;\n }\n\n /**\n * Unmount the component\n */\n unmount() {\n this.component = null;\n this.result = null;\n }\n}\n\n/**\n * Create a test renderer\n * \n * @param {Object} component - Component to render\n * @param {Object} [options] - Render options\n * @returns {TestRenderer} Test renderer instance\n * \n * @example\n * const renderer = createTestRenderer(MyComponent);\n * const result = renderer.render();\n * expect(result.getByText('Hello')).toBeTruthy();\n * \n * // Update and re-render\n * renderer.update(UpdatedComponent);\n * expect(renderer.getRenderCount()).toBe(2);\n */\nexport function createTestRenderer(component, options = {}) {\n return new TestRenderer(component, options);\n}\n\n/**\n * Shallow render a component (only render top level)\n * \n * @param {Object} component - Component to render\n * @returns {Object} Shallow rendered component\n */\nexport function shallowRender(component) {\n // Clone component without rendering children\n const shallow = { ...component };\n \n Object.keys(shallow).forEach(key => {\n if (shallow[key] && typeof shallow[key] === 'object') {\n if (shallow[key].children) {\n shallow[key] = {\n ...shallow[key],\n children: Array.isArray(shallow[key].children)\n ? shallow[key].children.map(() => ({ _shallow: true }))\n : { _shallow: true }\n };\n }\n }\n });\n \n return shallow;\n}\n\n/**\n * Export all testing utilities\n */\nexport default {\n renderComponent,\n renderComponentAsync,\n createTestRenderer,\n shallowRender,\n TestRenderer,\n TestRendererResult\n};\n", "/**\n * Coherent.js Test Utilities\n * \n * Helper functions for testing Coherent.js components\n * \n * @module testing/test-utils\n */\n\n/**\n * Simulate an event on an element\n * \n * @param {Object} element - Element to fire event on\n * @param {string} eventType - Type of event (click, change, etc.)\n * @param {Object} [eventData] - Additional event data\n */\nexport function fireEvent(element, eventType, eventData = {}) {\n if (!element) {\n throw new Error('Element is required for fireEvent');\n }\n \n // In a test environment, we simulate the event\n const event = {\n type: eventType,\n target: element,\n currentTarget: element,\n preventDefault: () => {},\n stopPropagation: () => {},\n ...eventData\n };\n \n // If element has an event handler, call it\n const handlerName = `on${eventType}`;\n if (element[handlerName] && typeof element[handlerName] === 'function') {\n element[handlerName](event);\n }\n \n return event;\n}\n\n/**\n * Common event helpers\n */\nexport const fireEvent_click = (element, eventData) => \n fireEvent(element, 'click', eventData);\n\nexport const fireEvent_change = (element, value) => \n fireEvent(element, 'change', { target: { value } });\n\nexport const fireEvent_input = (element, value) => \n fireEvent(element, 'input', { target: { value } });\n\nexport const fireEvent_submit = (element, eventData) => \n fireEvent(element, 'submit', eventData);\n\nexport const fireEvent_keyDown = (element, key) => \n fireEvent(element, 'keydown', { key });\n\nexport const fireEvent_keyUp = (element, key) => \n fireEvent(element, 'keyup', { key });\n\nexport const fireEvent_focus = (element) => \n fireEvent(element, 'focus');\n\nexport const fireEvent_blur = (element) => \n fireEvent(element, 'blur');\n\n/**\n * Wait for a condition to be true\n * \n * @param {Function} condition - Condition function\n * @param {Object} [options] - Wait options\n * @param {number} [options.timeout=1000] - Timeout in ms\n * @param {number} [options.interval=50] - Check interval in ms\n * @returns {Promise<void>}\n * \n * @example\n * await waitFor(() => getByText('Loaded').exists, { timeout: 2000 });\n */\nexport function waitFor(condition, options = {}) {\n const { timeout = 1000, interval = 50 } = options;\n \n return new Promise((resolve, reject) => {\n const startTime = Date.now();\n \n const check = () => {\n try {\n if (condition()) {\n resolve();\n return;\n }\n } catch {\n // Condition threw an error, keep waiting\n }\n \n if (Date.now() - startTime >= timeout) {\n reject(new Error(`Timeout waiting for condition after ${timeout}ms`));\n return;\n }\n \n setTimeout(check, interval);\n };\n \n check();\n });\n}\n\n/**\n * Wait for element to appear\n * \n * @param {Function} queryFn - Query function that returns element\n * @param {Object} [options] - Wait options\n * @returns {Promise<Object>} Element\n */\nexport async function waitForElement(queryFn, options = {}) {\n let element = null;\n \n await waitFor(() => {\n element = queryFn();\n return element !== null;\n }, options);\n \n return element;\n}\n\n/**\n * Wait for element to disappear\n * \n * @param {Function} queryFn - Query function that returns element\n * @param {Object} [options] - Wait options\n * @returns {Promise<void>}\n */\nexport async function waitForElementToBeRemoved(queryFn, options = {}) {\n await waitFor(() => {\n const element = queryFn();\n return element === null;\n }, options);\n}\n\n/**\n * Act utility for batching updates\n * Useful for testing state changes\n * \n * @param {Function} callback - Callback to execute\n * @returns {Promise<void>}\n */\nexport async function act(callback) {\n await callback();\n // Allow any pending updates to flush\n await new Promise(resolve => setTimeout(resolve, 0));\n}\n\n/**\n * Create a mock function\n * \n * @param {Function} [implementation] - Optional implementation\n * @returns {Function} Mock function\n */\nexport function createMock(implementation) {\n const calls = [];\n const results = [];\n \n const mockFn = function(...args) {\n calls.push(args);\n \n let result;\n let error;\n \n try {\n result = implementation ? implementation(...args) : undefined;\n results.push({ type: 'return', value: result });\n } catch (err) {\n error = err;\n results.push({ type: 'throw', value: error });\n throw error;\n }\n \n return result;\n };\n \n // Add mock utilities\n mockFn.mock = {\n calls,\n results,\n instances: []\n };\n \n mockFn.mockClear = () => {\n calls.length = 0;\n results.length = 0;\n };\n \n mockFn.mockReset = () => {\n mockFn.mockClear();\n implementation = undefined;\n };\n \n mockFn.mockImplementation = (fn) => {\n implementation = fn;\n return mockFn;\n };\n \n mockFn.mockReturnValue = (value) => {\n implementation = () => value;\n return mockFn;\n };\n \n mockFn.mockResolvedValue = (value) => {\n implementation = () => Promise.resolve(value);\n return mockFn;\n };\n \n mockFn.mockRejectedValue = (error) => {\n implementation = () => Promise.reject(error);\n return mockFn;\n };\n \n return mockFn;\n}\n\n/**\n * Create a spy on an object method\n * \n * @param {Object} object - Object to spy on\n * @param {string} method - Method name\n * @returns {Function} Spy function\n */\nexport function createSpy(object, method) {\n const original = object[method];\n const spy = createMock(original.bind(object));\n \n object[method] = spy;\n \n spy.mockRestore = () => {\n object[method] = original;\n };\n \n return spy;\n}\n\n/**\n * Cleanup utility\n * Cleans up after tests\n */\nexport function cleanup() {\n // Clear any timers\n // Reset any global state\n // This would be expanded based on framework needs\n}\n\n/**\n * Within utility - scopes queries to a container\n * \n * @param {Object} container - Container result\n * @returns {Object} Scoped queries\n */\nexport function within(container) {\n return {\n getByTestId: (testId) => container.getByTestId(testId),\n queryByTestId: (testId) => container.queryByTestId(testId),\n getByText: (text) => container.getByText(text),\n queryByText: (text) => container.queryByText(text),\n getByClassName: (className) => container.getByClassName(className),\n queryByClassName: (className) => container.queryByClassName(className)\n };\n}\n\n/**\n * Screen utility - global queries\n * Useful for accessing rendered content without storing result\n */\nexport const screen = {\n _result: null,\n \n setResult(result) {\n this._result = result;\n },\n \n getByTestId(testId) {\n if (!this._result) throw new Error('No component rendered');\n return this._result.getByTestId(testId);\n },\n \n queryByTestId(testId) {\n if (!this._result) return null;\n return this._result.queryByTestId(testId);\n },\n \n getByText(text) {\n if (!this._result) throw new Error('No component rendered');\n return this._result.getByText(text);\n },\n \n queryByText(text) {\n if (!this._result) return null;\n return this._result.queryByText(text);\n },\n \n getByClassName(className) {\n if (!this._result) throw new Error('No component rendered');\n return this._result.getByClassName(className);\n },\n \n queryByClassName(className) {\n if (!this._result) return null;\n return this._result.queryByClassName(className);\n },\n \n debug() {\n if (this._result) {\n this._result.debug();\n }\n }\n};\n\n/**\n * User event simulation\n * More realistic event simulation than fireEvent\n */\nexport const userEvent = {\n /**\n * Simulate user typing\n */\n type: async (element, text, options = {}) => {\n const { delay = 0 } = options;\n \n for (const char of text) {\n fireEvent_keyDown(element, char);\n fireEvent_input(element, element.value + char);\n fireEvent_keyUp(element, char);\n \n if (delay > 0) {\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n },\n \n /**\n * Simulate user click\n */\n click: async (element) => {\n fireEvent_focus(element);\n fireEvent_click(element);\n },\n \n /**\n * Simulate user double click\n */\n dblClick: async (element) => {\n await userEvent.click(element);\n await userEvent.click(element);\n },\n \n /**\n * Simulate user clearing input\n */\n clear: async (element) => {\n fireEvent_input(element, '');\n fireEvent_change(element, '');\n },\n \n /**\n * Simulate user selecting option\n */\n selectOptions: async (element, values) => {\n const valueArray = Array.isArray(values) ? values : [values];\n fireEvent_change(element, valueArray[0]);\n },\n \n /**\n * Simulate user tab navigation\n */\n tab: async () => {\n // Simulate tab key\n const activeElement = document.activeElement;\n if (activeElement) {\n fireEvent_keyDown(activeElement, 'Tab');\n fireEvent_blur(activeElement);\n }\n }\n};\n\n/**\n * Export all utilities\n */\nexport default {\n fireEvent,\n waitFor,\n waitForElement,\n waitForElementToBeRemoved,\n act,\n createMock,\n createSpy,\n cleanup,\n within,\n screen,\n userEvent\n};\n", "/**\n * Coherent.js Custom Test Matchers\n * \n * Custom matchers for testing Coherent.js components\n * Compatible with Vitest, Jest, and other testing frameworks\n * \n * @module testing/matchers\n */\n\n/**\n * Custom matchers for Coherent.js testing\n */\nexport const customMatchers = {\n /**\n * Check if element has specific text\n */\n toHaveText(received, expected) {\n const pass = received && received.text === expected;\n \n return {\n pass,\n message: () => pass\n ? `Expected element not to have text \"${expected}\"`\n : `Expected element to have text \"${expected}\", but got \"${received?.text || 'null'}\"`\n };\n },\n\n /**\n * Check if element contains text\n */\n toContainText(received, expected) {\n const pass = received && received.text && received.text.includes(expected);\n \n return {\n pass,\n message: () => pass\n ? `Expected element not to contain text \"${expected}\"`\n : `Expected element to contain text \"${expected}\", but got \"${received?.text || 'null'}\"`\n };\n },\n\n /**\n * Check if element has specific class\n */\n toHaveClass(received, expected) {\n const pass = received && received.className && received.className.includes(expected);\n \n return {\n pass,\n message: () => pass\n ? `Expected element not to have class \"${expected}\"`\n : `Expected element to have class \"${expected}\", but got \"${received?.className || 'null'}\"`\n };\n },\n\n /**\n * Check if element exists\n */\n toBeInTheDocument(received) {\n const pass = received && received.exists === true;\n \n return {\n pass,\n message: () => pass\n ? 'Expected element not to be in the document'\n : 'Expected element to be in the document'\n };\n },\n\n /**\n * Check if element is visible (has content)\n */\n toBeVisible(received) {\n const pass = received && received.text && received.text.trim().length > 0;\n \n return {\n pass,\n message: () => pass\n ? 'Expected element not to be visible'\n : 'Expected element to be visible (have text content)'\n };\n },\n\n /**\n * Check if element is empty\n */\n toBeEmpty(received) {\n const pass = !received || !received.text || received.text.trim().length === 0;\n \n return {\n pass,\n message: () => pass\n ? 'Expected element not to be empty'\n : 'Expected element to be empty'\n };\n },\n\n /**\n * Check if HTML contains specific string\n */\n toContainHTML(received, expected) {\n const html = received?.html || received;\n const pass = typeof html === 'string' && html.includes(expected);\n \n return {\n pass,\n message: () => pass\n ? `Expected HTML not to contain \"${expected}\"`\n : `Expected HTML to contain \"${expected}\"`\n };\n },\n\n /**\n * Check if element has attribute\n */\n toHaveAttribute(received, attribute, value) {\n const html = received?.html || '';\n const regex = new RegExp(`${attribute}=\"([^\"]*)\"`, 'i');\n const match = html.match(regex);\n \n const pass = value !== undefined\n ? match && match[1] === value\n : match !== null;\n \n return {\n pass,\n message: () => {\n if (value !== undefined) {\n return pass\n ? `Expected element not to have attribute ${attribute}=\"${value}\"`\n : `Expected element to have attribute ${attribute}=\"${value}\", but got \"${match?.[1] || 'none'}\"`;\n }\n return pass\n ? `Expected element not to have attribute ${attribute}`\n : `Expected element to have attribute ${attribute}`;\n }\n };\n },\n\n /**\n * Check if component matches snapshot\n */\n toMatchSnapshot(received) {\n const _snapshot = received?.toSnapshot ? received.toSnapshot() : received;\n \n // This would integrate with the testing framework's snapshot system\n return {\n pass: true,\n message: () => 'Snapshot comparison'\n };\n },\n\n /**\n * Check if element has specific tag name\n */\n toHaveTagName(received, tagName) {\n const html = received?.html || '';\n const regex = new RegExp(`<${tagName}[^>]*>`, 'i');\n const pass = regex.test(html);\n \n return {\n pass,\n message: () => pass\n ? `Expected element not to have tag name \"${tagName}\"`\n : `Expected element to have tag name \"${tagName}\"`\n };\n },\n\n /**\n * Check if render result contains element\n */\n toContainElement(received, element) {\n const html = received?.html || received;\n const elementHtml = element?.html || element;\n const pass = typeof html === 'string' && html.includes(elementHtml);\n \n return {\n pass,\n message: () => pass\n ? 'Expected not to contain element'\n : 'Expected to contain element'\n };\n },\n\n /**\n * Check if mock was called\n */\n toHaveBeenCalled(received) {\n const pass = received?.mock?.calls?.length > 0;\n \n return {\n pass,\n message: () => pass\n ? 'Expected mock not to have been called'\n : 'Expected mock to have been called'\n };\n },\n\n /**\n * Check if mock was called with specific args\n */\n toHaveBeenCalledWith(received, ...expectedArgs) {\n const calls = received?.mock?.calls || [];\n const pass = calls.some(call => \n call.length === expectedArgs.length &&\n call.every((arg, i) => arg === expectedArgs[i])\n );\n \n return {\n pass,\n message: () => pass\n ? `Expected mock not to have been called with ${JSON.stringify(expectedArgs)}`\n : `Expected mock to have been called with ${JSON.stringify(expectedArgs)}`\n };\n },\n\n /**\n * Check if mock was called N times\n */\n toHaveBeenCalledTimes(received, times) {\n const callCount = received?.mock?.calls?.length || 0;\n const pass = callCount === times;\n \n return {\n pass,\n message: () => pass\n ? `Expected mock not to have been called ${times} times`\n : `Expected mock to have been called ${times} times, but was called ${callCount} times`\n };\n },\n\n /**\n * Check if component rendered successfully\n */\n toRenderSuccessfully(received) {\n const pass = received && received.html && received.html.length > 0;\n \n return {\n pass,\n message: () => pass\n ? 'Expected component not to render successfully'\n : 'Expected component to render successfully'\n };\n },\n\n /**\n * Check if HTML is valid\n */\n toBeValidHTML(received) {\n const html = received?.html || received;\n \n // Basic HTML validation\n const openTags = (html.match(/<[^/][^>]*>/g) || []).length;\n const closeTags = (html.match(/<\\/[^>]+>/g) || []).length;\n const selfClosing = (html.match(/<[^>]+\\/>/g) || []).length;\n \n const pass = openTags === closeTags + selfClosing;\n \n return {\n pass,\n message: () => pass\n ? 'Expected HTML not to be valid'\n : `Expected HTML to be valid (open: ${openTags}, close: ${closeTags}, self-closing: ${selfClosing})`\n };\n }\n};\n\n/**\n * Extend expect with custom matchers\n * \n * @param {Object} expect - Expect function from testing framework\n * \n * @example\n * import { expect } from 'vitest';\n * import { extendExpect } from '@coherent.js/testing/matchers';\n * \n * extendExpect(expect);\n * \n * // Now you can use custom matchers\n * expect(element).toHaveText('Hello');\n */\nexport function extendExpect(expect) {\n if (expect && expect.extend) {\n expect.extend(customMatchers);\n } else {\n console.warn('Could not extend expect - expect.extend not available');\n }\n}\n\n/**\n * Create assertion helpers\n */\nexport const assertions = {\n /**\n * Assert element has text\n */\n assertHasText(element, text) {\n if (!element || element.text !== text) {\n throw new Error(`Expected element to have text \"${text}\", but got \"${element?.text || 'null'}\"`);\n }\n },\n\n /**\n * Assert element exists\n */\n assertExists(element) {\n if (!element || !element.exists) {\n throw new Error('Expected element to exist');\n }\n },\n\n /**\n * Assert element has class\n */\n assertHasClass(element, className) {\n if (!element || !element.className || !element.className.includes(className)) {\n throw new Error(`Expected element to have class \"${className}\"`);\n }\n },\n\n /**\n * Assert HTML contains string\n */\n assertContainsHTML(html, substring) {\n const htmlString = html?.html || html;\n if (!htmlString || !htmlString.includes(substring)) {\n throw new Error(`Expected HTML to contain \"${substring}\"`);\n }\n },\n\n /**\n * Assert component rendered\n */\n assertRendered(result) {\n if (!result || !result.html || result.html.length === 0) {\n throw new Error('Expected component to render');\n }\n }\n};\n\n/**\n * Export all matchers and utilities\n */\nexport default {\n customMatchers,\n extendExpect,\n assertions\n};\n", "/**\n * Coherent.js Testing Utilities\n * \n * Complete testing solution for Coherent.js applications\n * \n * @module testing\n */\n\n// Export test renderer\nexport {\n renderComponent,\n renderComponentAsync,\n createTestRenderer,\n shallowRender,\n TestRenderer,\n TestRendererResult\n} from './test-renderer.js';\n\n// Export test utilities\nexport {\n fireEvent,\n waitFor,\n waitForElement,\n waitForElementToBeRemoved,\n act,\n createMock,\n createSpy,\n cleanup,\n within,\n screen,\n userEvent\n} from './test-utils.js';\n\n// Export matchers\nexport {\n customMatchers,\n extendExpect,\n assertions\n} from './matchers.js';\n\n// Re-import for default export\nimport {\n renderComponent as _renderComponent,\n renderComponentAsync as _renderComponentAsync,\n createTestRenderer as _createTestRenderer,\n shallowRender as _shallowRender\n} from './test-renderer.js';\n\nimport {\n fireEvent as _fireEvent,\n waitFor as _waitFor,\n waitForElement as _waitForElement,\n waitForElementToBeRemoved as _waitForElementToBeRemoved,\n act as _act,\n createMock as _createMock,\n createSpy as _createSpy,\n cleanup as _cleanup,\n within as _within,\n screen as _screen,\n userEvent as _userEvent\n} from './test-utils.js';\n\nimport {\n customMatchers as _customMatchers,\n extendExpect as _extendExpect,\n assertions as _assertions\n} from './matchers.js';\n\n// Default export with all utilities\nexport default {\n // Renderer\n renderComponent: _renderComponent,\n renderComponentAsync: _renderComponentAsync,\n createTestRenderer: _createTestRenderer,\n shallowRender: _shallowRender,\n\n // Utilities\n fireEvent: _fireEvent,\n waitFor: _waitFor,\n waitForElement: _waitForElement,\n waitForElementToBeRemoved: _waitForElementToBeRemoved,\n act: _act,\n createMock: _createMock,\n createSpy: _createSpy,\n cleanup: _cleanup,\n within: _within,\n screen: _screen,\n userEvent: _userEvent,\n\n // Matchers\n customMatchers: _customMatchers,\n extendExpect: _extendExpect,\n assertions: _assertions\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/matchers.js
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
// src/matchers.js
|
|
2
|
+
var customMatchers = {
|
|
3
|
+
/**
|
|
4
|
+
* Check if element has specific text
|
|
5
|
+
*/
|
|
6
|
+
toHaveText(received, expected) {
|
|
7
|
+
const pass = received && received.text === expected;
|
|
8
|
+
return {
|
|
9
|
+
pass,
|
|
10
|
+
message: () => pass ? `Expected element not to have text "${expected}"` : `Expected element to have text "${expected}", but got "${received?.text || "null"}"`
|
|
11
|
+
};
|
|
12
|
+
},
|
|
13
|
+
/**
|
|
14
|
+
* Check if element contains text
|
|
15
|
+
*/
|
|
16
|
+
toContainText(received, expected) {
|
|
17
|
+
const pass = received && received.text && received.text.includes(expected);
|
|
18
|
+
return {
|
|
19
|
+
pass,
|
|
20
|
+
message: () => pass ? `Expected element not to contain text "${expected}"` : `Expected element to contain text "${expected}", but got "${received?.text || "null"}"`
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
/**
|
|
24
|
+
* Check if element has specific class
|
|
25
|
+
*/
|
|
26
|
+
toHaveClass(received, expected) {
|
|
27
|
+
const pass = received && received.className && received.className.includes(expected);
|
|
28
|
+
return {
|
|
29
|
+
pass,
|
|
30
|
+
message: () => pass ? `Expected element not to have class "${expected}"` : `Expected element to have class "${expected}", but got "${received?.className || "null"}"`
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
/**
|
|
34
|
+
* Check if element exists
|
|
35
|
+
*/
|
|
36
|
+
toBeInTheDocument(received) {
|
|
37
|
+
const pass = received && received.exists === true;
|
|
38
|
+
return {
|
|
39
|
+
pass,
|
|
40
|
+
message: () => pass ? "Expected element not to be in the document" : "Expected element to be in the document"
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
/**
|
|
44
|
+
* Check if element is visible (has content)
|
|
45
|
+
*/
|
|
46
|
+
toBeVisible(received) {
|
|
47
|
+
const pass = received && received.text && received.text.trim().length > 0;
|
|
48
|
+
return {
|
|
49
|
+
pass,
|
|
50
|
+
message: () => pass ? "Expected element not to be visible" : "Expected element to be visible (have text content)"
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
/**
|
|
54
|
+
* Check if element is empty
|
|
55
|
+
*/
|
|
56
|
+
toBeEmpty(received) {
|
|
57
|
+
const pass = !received || !received.text || received.text.trim().length === 0;
|
|
58
|
+
return {
|
|
59
|
+
pass,
|
|
60
|
+
message: () => pass ? "Expected element not to be empty" : "Expected element to be empty"
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
/**
|
|
64
|
+
* Check if HTML contains specific string
|
|
65
|
+
*/
|
|
66
|
+
toContainHTML(received, expected) {
|
|
67
|
+
const html = received?.html || received;
|
|
68
|
+
const pass = typeof html === "string" && html.includes(expected);
|
|
69
|
+
return {
|
|
70
|
+
pass,
|
|
71
|
+
message: () => pass ? `Expected HTML not to contain "${expected}"` : `Expected HTML to contain "${expected}"`
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
/**
|
|
75
|
+
* Check if element has attribute
|
|
76
|
+
*/
|
|
77
|
+
toHaveAttribute(received, attribute, value) {
|
|
78
|
+
const html = received?.html || "";
|
|
79
|
+
const regex = new RegExp(`${attribute}="([^"]*)"`, "i");
|
|
80
|
+
const match = html.match(regex);
|
|
81
|
+
const pass = value !== void 0 ? match && match[1] === value : match !== null;
|
|
82
|
+
return {
|
|
83
|
+
pass,
|
|
84
|
+
message: () => {
|
|
85
|
+
if (value !== void 0) {
|
|
86
|
+
return pass ? `Expected element not to have attribute ${attribute}="${value}"` : `Expected element to have attribute ${attribute}="${value}", but got "${match?.[1] || "none"}"`;
|
|
87
|
+
}
|
|
88
|
+
return pass ? `Expected element not to have attribute ${attribute}` : `Expected element to have attribute ${attribute}`;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
/**
|
|
93
|
+
* Check if component matches snapshot
|
|
94
|
+
*/
|
|
95
|
+
toMatchSnapshot(received) {
|
|
96
|
+
const _snapshot = received?.toSnapshot ? received.toSnapshot() : received;
|
|
97
|
+
return {
|
|
98
|
+
pass: true,
|
|
99
|
+
message: () => "Snapshot comparison"
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
/**
|
|
103
|
+
* Check if element has specific tag name
|
|
104
|
+
*/
|
|
105
|
+
toHaveTagName(received, tagName) {
|
|
106
|
+
const html = received?.html || "";
|
|
107
|
+
const regex = new RegExp(`<${tagName}[^>]*>`, "i");
|
|
108
|
+
const pass = regex.test(html);
|
|
109
|
+
return {
|
|
110
|
+
pass,
|
|
111
|
+
message: () => pass ? `Expected element not to have tag name "${tagName}"` : `Expected element to have tag name "${tagName}"`
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
/**
|
|
115
|
+
* Check if render result contains element
|
|
116
|
+
*/
|
|
117
|
+
toContainElement(received, element) {
|
|
118
|
+
const html = received?.html || received;
|
|
119
|
+
const elementHtml = element?.html || element;
|
|
120
|
+
const pass = typeof html === "string" && html.includes(elementHtml);
|
|
121
|
+
return {
|
|
122
|
+
pass,
|
|
123
|
+
message: () => pass ? "Expected not to contain element" : "Expected to contain element"
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
/**
|
|
127
|
+
* Check if mock was called
|
|
128
|
+
*/
|
|
129
|
+
toHaveBeenCalled(received) {
|
|
130
|
+
const pass = received?.mock?.calls?.length > 0;
|
|
131
|
+
return {
|
|
132
|
+
pass,
|
|
133
|
+
message: () => pass ? "Expected mock not to have been called" : "Expected mock to have been called"
|
|
134
|
+
};
|
|
135
|
+
},
|
|
136
|
+
/**
|
|
137
|
+
* Check if mock was called with specific args
|
|
138
|
+
*/
|
|
139
|
+
toHaveBeenCalledWith(received, ...expectedArgs) {
|
|
140
|
+
const calls = received?.mock?.calls || [];
|
|
141
|
+
const pass = calls.some(
|
|
142
|
+
(call) => call.length === expectedArgs.length && call.every((arg, i) => arg === expectedArgs[i])
|
|
143
|
+
);
|
|
144
|
+
return {
|
|
145
|
+
pass,
|
|
146
|
+
message: () => pass ? `Expected mock not to have been called with ${JSON.stringify(expectedArgs)}` : `Expected mock to have been called with ${JSON.stringify(expectedArgs)}`
|
|
147
|
+
};
|
|
148
|
+
},
|
|
149
|
+
/**
|
|
150
|
+
* Check if mock was called N times
|
|
151
|
+
*/
|
|
152
|
+
toHaveBeenCalledTimes(received, times) {
|
|
153
|
+
const callCount = received?.mock?.calls?.length || 0;
|
|
154
|
+
const pass = callCount === times;
|
|
155
|
+
return {
|
|
156
|
+
pass,
|
|
157
|
+
message: () => pass ? `Expected mock not to have been called ${times} times` : `Expected mock to have been called ${times} times, but was called ${callCount} times`
|
|
158
|
+
};
|
|
159
|
+
},
|
|
160
|
+
/**
|
|
161
|
+
* Check if component rendered successfully
|
|
162
|
+
*/
|
|
163
|
+
toRenderSuccessfully(received) {
|
|
164
|
+
const pass = received && received.html && received.html.length > 0;
|
|
165
|
+
return {
|
|
166
|
+
pass,
|
|
167
|
+
message: () => pass ? "Expected component not to render successfully" : "Expected component to render successfully"
|
|
168
|
+
};
|
|
169
|
+
},
|
|
170
|
+
/**
|
|
171
|
+
* Check if HTML is valid
|
|
172
|
+
*/
|
|
173
|
+
toBeValidHTML(received) {
|
|
174
|
+
const html = received?.html || received;
|
|
175
|
+
const openTags = (html.match(/<[^/][^>]*>/g) || []).length;
|
|
176
|
+
const closeTags = (html.match(/<\/[^>]+>/g) || []).length;
|
|
177
|
+
const selfClosing = (html.match(/<[^>]+\/>/g) || []).length;
|
|
178
|
+
const pass = openTags === closeTags + selfClosing;
|
|
179
|
+
return {
|
|
180
|
+
pass,
|
|
181
|
+
message: () => pass ? "Expected HTML not to be valid" : `Expected HTML to be valid (open: ${openTags}, close: ${closeTags}, self-closing: ${selfClosing})`
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
function extendExpect(expect) {
|
|
186
|
+
if (expect && expect.extend) {
|
|
187
|
+
expect.extend(customMatchers);
|
|
188
|
+
} else {
|
|
189
|
+
console.warn("Could not extend expect - expect.extend not available");
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
var assertions = {
|
|
193
|
+
/**
|
|
194
|
+
* Assert element has text
|
|
195
|
+
*/
|
|
196
|
+
assertHasText(element, text) {
|
|
197
|
+
if (!element || element.text !== text) {
|
|
198
|
+
throw new Error(`Expected element to have text "${text}", but got "${element?.text || "null"}"`);
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
/**
|
|
202
|
+
* Assert element exists
|
|
203
|
+
*/
|
|
204
|
+
assertExists(element) {
|
|
205
|
+
if (!element || !element.exists) {
|
|
206
|
+
throw new Error("Expected element to exist");
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
/**
|
|
210
|
+
* Assert element has class
|
|
211
|
+
*/
|
|
212
|
+
assertHasClass(element, className) {
|
|
213
|
+
if (!element || !element.className || !element.className.includes(className)) {
|
|
214
|
+
throw new Error(`Expected element to have class "${className}"`);
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
/**
|
|
218
|
+
* Assert HTML contains string
|
|
219
|
+
*/
|
|
220
|
+
assertContainsHTML(html, substring) {
|
|
221
|
+
const htmlString = html?.html || html;
|
|
222
|
+
if (!htmlString || !htmlString.includes(substring)) {
|
|
223
|
+
throw new Error(`Expected HTML to contain "${substring}"`);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
/**
|
|
227
|
+
* Assert component rendered
|
|
228
|
+
*/
|
|
229
|
+
assertRendered(result) {
|
|
230
|
+
if (!result || !result.html || result.html.length === 0) {
|
|
231
|
+
throw new Error("Expected component to render");
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
var matchers_default = {
|
|
236
|
+
customMatchers,
|
|
237
|
+
extendExpect,
|
|
238
|
+
assertions
|
|
239
|
+
};
|
|
240
|
+
export {
|
|
241
|
+
assertions,
|
|
242
|
+
customMatchers,
|
|
243
|
+
matchers_default as default,
|
|
244
|
+
extendExpect
|
|
245
|
+
};
|
|
246
|
+
//# sourceMappingURL=matchers.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/matchers.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * Coherent.js Custom Test Matchers\n * \n * Custom matchers for testing Coherent.js components\n * Compatible with Vitest, Jest, and other testing frameworks\n * \n * @module testing/matchers\n */\n\n/**\n * Custom matchers for Coherent.js testing\n */\nexport const customMatchers = {\n /**\n * Check if element has specific text\n */\n toHaveText(received, expected) {\n const pass = received && received.text === expected;\n \n return {\n pass,\n message: () => pass\n ? `Expected element not to have text \"${expected}\"`\n : `Expected element to have text \"${expected}\", but got \"${received?.text || 'null'}\"`\n };\n },\n\n /**\n * Check if element contains text\n */\n toContainText(received, expected) {\n const pass = received && received.text && received.text.includes(expected);\n \n return {\n pass,\n message: () => pass\n ? `Expected element not to contain text \"${expected}\"`\n : `Expected element to contain text \"${expected}\", but got \"${received?.text || 'null'}\"`\n };\n },\n\n /**\n * Check if element has specific class\n */\n toHaveClass(received, expected) {\n const pass = received && received.className && received.className.includes(expected);\n \n return {\n pass,\n message: () => pass\n ? `Expected element not to have class \"${expected}\"`\n : `Expected element to have class \"${expected}\", but got \"${received?.className || 'null'}\"`\n };\n },\n\n /**\n * Check if element exists\n */\n toBeInTheDocument(received) {\n const pass = received && received.exists === true;\n \n return {\n pass,\n message: () => pass\n ? 'Expected element not to be in the document'\n : 'Expected element to be in the document'\n };\n },\n\n /**\n * Check if element is visible (has content)\n */\n toBeVisible(received) {\n const pass = received && received.text && received.text.trim().length > 0;\n \n return {\n pass,\n message: () => pass\n ? 'Expected element not to be visible'\n : 'Expected element to be visible (have text content)'\n };\n },\n\n /**\n * Check if element is empty\n */\n toBeEmpty(received) {\n const pass = !received || !received.text || received.text.trim().length === 0;\n \n return {\n pass,\n message: () => pass\n ? 'Expected element not to be empty'\n : 'Expected element to be empty'\n };\n },\n\n /**\n * Check if HTML contains specific string\n */\n toContainHTML(received, expected) {\n const html = received?.html || received;\n const pass = typeof html === 'string' && html.includes(expected);\n \n return {\n pass,\n message: () => pass\n ? `Expected HTML not to contain \"${expected}\"`\n : `Expected HTML to contain \"${expected}\"`\n };\n },\n\n /**\n * Check if element has attribute\n */\n toHaveAttribute(received, attribute, value) {\n const html = received?.html || '';\n const regex = new RegExp(`${attribute}=\"([^\"]*)\"`, 'i');\n const match = html.match(regex);\n \n const pass = value !== undefined\n ? match && match[1] === value\n : match !== null;\n \n return {\n pass,\n message: () => {\n if (value !== undefined) {\n return pass\n ? `Expected element not to have attribute ${attribute}=\"${value}\"`\n : `Expected element to have attribute ${attribute}=\"${value}\", but got \"${match?.[1] || 'none'}\"`;\n }\n return pass\n ? `Expected element not to have attribute ${attribute}`\n : `Expected element to have attribute ${attribute}`;\n }\n };\n },\n\n /**\n * Check if component matches snapshot\n */\n toMatchSnapshot(received) {\n const _snapshot = received?.toSnapshot ? received.toSnapshot() : received;\n \n // This would integrate with the testing framework's snapshot system\n return {\n pass: true,\n message: () => 'Snapshot comparison'\n };\n },\n\n /**\n * Check if element has specific tag name\n */\n toHaveTagName(received, tagName) {\n const html = received?.html || '';\n const regex = new RegExp(`<${tagName}[^>]*>`, 'i');\n const pass = regex.test(html);\n \n return {\n pass,\n message: () => pass\n ? `Expected element not to have tag name \"${tagName}\"`\n : `Expected element to have tag name \"${tagName}\"`\n };\n },\n\n /**\n * Check if render result contains element\n */\n toContainElement(received, element) {\n const html = received?.html || received;\n const elementHtml = element?.html || element;\n const pass = typeof html === 'string' && html.includes(elementHtml);\n \n return {\n pass,\n message: () => pass\n ? 'Expected not to contain element'\n : 'Expected to contain element'\n };\n },\n\n /**\n * Check if mock was called\n */\n toHaveBeenCalled(received) {\n const pass = received?.mock?.calls?.length > 0;\n \n return {\n pass,\n message: () => pass\n ? 'Expected mock not to have been called'\n : 'Expected mock to have been called'\n };\n },\n\n /**\n * Check if mock was called with specific args\n */\n toHaveBeenCalledWith(received, ...expectedArgs) {\n const calls = received?.mock?.calls || [];\n const pass = calls.some(call => \n call.length === expectedArgs.length &&\n call.every((arg, i) => arg === expectedArgs[i])\n );\n \n return {\n pass,\n message: () => pass\n ? `Expected mock not to have been called with ${JSON.stringify(expectedArgs)}`\n : `Expected mock to have been called with ${JSON.stringify(expectedArgs)}`\n };\n },\n\n /**\n * Check if mock was called N times\n */\n toHaveBeenCalledTimes(received, times) {\n const callCount = received?.mock?.calls?.length || 0;\n const pass = callCount === times;\n \n return {\n pass,\n message: () => pass\n ? `Expected mock not to have been called ${times} times`\n : `Expected mock to have been called ${times} times, but was called ${callCount} times`\n };\n },\n\n /**\n * Check if component rendered successfully\n */\n toRenderSuccessfully(received) {\n const pass = received && received.html && received.html.length > 0;\n \n return {\n pass,\n message: () => pass\n ? 'Expected component not to render successfully'\n : 'Expected component to render successfully'\n };\n },\n\n /**\n * Check if HTML is valid\n */\n toBeValidHTML(received) {\n const html = received?.html || received;\n \n // Basic HTML validation\n const openTags = (html.match(/<[^/][^>]*>/g) || []).length;\n const closeTags = (html.match(/<\\/[^>]+>/g) || []).length;\n const selfClosing = (html.match(/<[^>]+\\/>/g) || []).length;\n \n const pass = openTags === closeTags + selfClosing;\n \n return {\n pass,\n message: () => pass\n ? 'Expected HTML not to be valid'\n : `Expected HTML to be valid (open: ${openTags}, close: ${closeTags}, self-closing: ${selfClosing})`\n };\n }\n};\n\n/**\n * Extend expect with custom matchers\n * \n * @param {Object} expect - Expect function from testing framework\n * \n * @example\n * import { expect } from 'vitest';\n * import { extendExpect } from '@coherent.js/testing/matchers';\n * \n * extendExpect(expect);\n * \n * // Now you can use custom matchers\n * expect(element).toHaveText('Hello');\n */\nexport function extendExpect(expect) {\n if (expect && expect.extend) {\n expect.extend(customMatchers);\n } else {\n console.warn('Could not extend expect - expect.extend not available');\n }\n}\n\n/**\n * Create assertion helpers\n */\nexport const assertions = {\n /**\n * Assert element has text\n */\n assertHasText(element, text) {\n if (!element || element.text !== text) {\n throw new Error(`Expected element to have text \"${text}\", but got \"${element?.text || 'null'}\"`);\n }\n },\n\n /**\n * Assert element exists\n */\n assertExists(element) {\n if (!element || !element.exists) {\n throw new Error('Expected element to exist');\n }\n },\n\n /**\n * Assert element has class\n */\n assertHasClass(element, className) {\n if (!element || !element.className || !element.className.includes(className)) {\n throw new Error(`Expected element to have class \"${className}\"`);\n }\n },\n\n /**\n * Assert HTML contains string\n */\n assertContainsHTML(html, substring) {\n const htmlString = html?.html || html;\n if (!htmlString || !htmlString.includes(substring)) {\n throw new Error(`Expected HTML to contain \"${substring}\"`);\n }\n },\n\n /**\n * Assert component rendered\n */\n assertRendered(result) {\n if (!result || !result.html || result.html.length === 0) {\n throw new Error('Expected component to render');\n }\n }\n};\n\n/**\n * Export all matchers and utilities\n */\nexport default {\n customMatchers,\n extendExpect,\n assertions\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// src/test-renderer.js
|
|
2
|
+
import { render } from "@coherent.js/core";
|
|
3
|
+
var TestRendererResult = class {
|
|
4
|
+
constructor(component, html, container = null) {
|
|
5
|
+
this.component = component;
|
|
6
|
+
this.html = html;
|
|
7
|
+
this.container = container;
|
|
8
|
+
this.queries = /* @__PURE__ */ new Map();
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get element by test ID
|
|
12
|
+
* @param {string} testId - Test ID to search for
|
|
13
|
+
* @returns {Object|null} Element or null
|
|
14
|
+
*/
|
|
15
|
+
getByTestId(testId) {
|
|
16
|
+
const regex = new RegExp(`data-testid="${testId}"[^>]*>([^<]*)<`, "i");
|
|
17
|
+
const match = this.html.match(regex);
|
|
18
|
+
if (!match) {
|
|
19
|
+
throw new Error(`Unable to find element with testId: ${testId}`);
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
text: match[1],
|
|
23
|
+
html: match[0],
|
|
24
|
+
testId,
|
|
25
|
+
exists: true
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Query element by test ID (returns null if not found)
|
|
30
|
+
* @param {string} testId - Test ID to search for
|
|
31
|
+
* @returns {Object|null} Element or null
|
|
32
|
+
*/
|
|
33
|
+
queryByTestId(testId) {
|
|
34
|
+
try {
|
|
35
|
+
return this.getByTestId(testId);
|
|
36
|
+
} catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get element by text content
|
|
42
|
+
* @param {string|RegExp} text - Text to search for
|
|
43
|
+
* @returns {Object} Element
|
|
44
|
+
*/
|
|
45
|
+
getByText(text) {
|
|
46
|
+
const regex = typeof text === "string" ? new RegExp(`>([^<]*${text}[^<]*)<`, "i") : new RegExp(`>([^<]*)<`, "i");
|
|
47
|
+
const match = this.html.match(regex);
|
|
48
|
+
if (!match || typeof text === "string" && !match[1].includes(text)) {
|
|
49
|
+
throw new Error(`Unable to find element with text: ${text}`);
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
text: match[1],
|
|
53
|
+
html: match[0],
|
|
54
|
+
exists: true
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Query element by text (returns null if not found)
|
|
59
|
+
* @param {string|RegExp} text - Text to search for
|
|
60
|
+
* @returns {Object|null} Element or null
|
|
61
|
+
*/
|
|
62
|
+
queryByText(text) {
|
|
63
|
+
try {
|
|
64
|
+
return this.getByText(text);
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get element by class name
|
|
71
|
+
* @param {string} className - Class name to search for
|
|
72
|
+
* @returns {Object} Element
|
|
73
|
+
*/
|
|
74
|
+
getByClassName(className) {
|
|
75
|
+
const regex = new RegExp(`class="[^"]*${className}[^"]*"[^>]*>([^<]*)<`, "i");
|
|
76
|
+
const match = this.html.match(regex);
|
|
77
|
+
if (!match) {
|
|
78
|
+
throw new Error(`Unable to find element with className: ${className}`);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
text: match[1],
|
|
82
|
+
html: match[0],
|
|
83
|
+
className,
|
|
84
|
+
exists: true
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Query element by class name (returns null if not found)
|
|
89
|
+
* @param {string} className - Class name to search for
|
|
90
|
+
* @returns {Object|null} Element or null
|
|
91
|
+
*/
|
|
92
|
+
queryByClassName(className) {
|
|
93
|
+
try {
|
|
94
|
+
return this.getByClassName(className);
|
|
95
|
+
} catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get all elements by tag name
|
|
101
|
+
* @param {string} tagName - Tag name to search for
|
|
102
|
+
* @returns {Array<Object>} Array of elements
|
|
103
|
+
*/
|
|
104
|
+
getAllByTagName(tagName) {
|
|
105
|
+
const regex = new RegExp(`<${tagName}[^>]*>([^<]*)</${tagName}>`, "gi");
|
|
106
|
+
const matches = [...this.html.matchAll(regex)];
|
|
107
|
+
return matches.map((match) => ({
|
|
108
|
+
text: match[1],
|
|
109
|
+
html: match[0],
|
|
110
|
+
tagName,
|
|
111
|
+
exists: true
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Check if element exists
|
|
116
|
+
* @param {string} selector - Selector (testId, text, className)
|
|
117
|
+
* @param {string} type - Type of selector ('testId', 'text', 'className')
|
|
118
|
+
* @returns {boolean} True if exists
|
|
119
|
+
*/
|
|
120
|
+
exists(selector, type = "testId") {
|
|
121
|
+
switch (type) {
|
|
122
|
+
case "testId":
|
|
123
|
+
return this.queryByTestId(selector) !== null;
|
|
124
|
+
case "text":
|
|
125
|
+
return this.queryByText(selector) !== null;
|
|
126
|
+
case "className":
|
|
127
|
+
return this.queryByClassName(selector) !== null;
|
|
128
|
+
default:
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get the rendered HTML
|
|
134
|
+
* @returns {string} HTML string
|
|
135
|
+
*/
|
|
136
|
+
getHTML() {
|
|
137
|
+
return this.html;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get the component
|
|
141
|
+
* @returns {Object} Component object
|
|
142
|
+
*/
|
|
143
|
+
getComponent() {
|
|
144
|
+
return this.component;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Create a snapshot of the rendered output
|
|
148
|
+
* @returns {string} Formatted HTML for snapshot testing
|
|
149
|
+
*/
|
|
150
|
+
toSnapshot() {
|
|
151
|
+
return this.html.replace(/>\s+</g, "><").trim();
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Debug: print the rendered HTML
|
|
155
|
+
*/
|
|
156
|
+
debug() {
|
|
157
|
+
console.log("=== Rendered HTML ===");
|
|
158
|
+
console.log(this.html);
|
|
159
|
+
console.log("=== Component ===");
|
|
160
|
+
console.log(JSON.stringify(this.component, null, 2));
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
function renderComponent(component, options = {}) {
|
|
164
|
+
const html = render(component, options);
|
|
165
|
+
return new TestRendererResult(component, html);
|
|
166
|
+
}
|
|
167
|
+
async function renderComponentAsync(component, props = {}, options = {}) {
|
|
168
|
+
const resolvedComponent = typeof component === "function" ? await component(props) : component;
|
|
169
|
+
const html = render(resolvedComponent, options);
|
|
170
|
+
return new TestRendererResult(resolvedComponent, html);
|
|
171
|
+
}
|
|
172
|
+
var TestRenderer = class {
|
|
173
|
+
constructor(component, options = {}) {
|
|
174
|
+
this.component = component;
|
|
175
|
+
this.options = options;
|
|
176
|
+
this.result = null;
|
|
177
|
+
this.renderCount = 0;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Render the component
|
|
181
|
+
* @returns {TestRendererResult} Render result
|
|
182
|
+
*/
|
|
183
|
+
render() {
|
|
184
|
+
this.renderCount++;
|
|
185
|
+
const html = render(this.component, this.options);
|
|
186
|
+
this.result = new TestRendererResult(this.component, html);
|
|
187
|
+
return this.result;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Update the component and re-render
|
|
191
|
+
* @param {Object} newComponent - Updated component
|
|
192
|
+
* @returns {TestRendererResult} Render result
|
|
193
|
+
*/
|
|
194
|
+
update(newComponent) {
|
|
195
|
+
this.component = newComponent;
|
|
196
|
+
return this.render();
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get the current result
|
|
200
|
+
* @returns {TestRendererResult|null} Current result
|
|
201
|
+
*/
|
|
202
|
+
getResult() {
|
|
203
|
+
return this.result;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Get render count
|
|
207
|
+
* @returns {number} Number of renders
|
|
208
|
+
*/
|
|
209
|
+
getRenderCount() {
|
|
210
|
+
return this.renderCount;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Unmount the component
|
|
214
|
+
*/
|
|
215
|
+
unmount() {
|
|
216
|
+
this.component = null;
|
|
217
|
+
this.result = null;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
function createTestRenderer(component, options = {}) {
|
|
221
|
+
return new TestRenderer(component, options);
|
|
222
|
+
}
|
|
223
|
+
function shallowRender(component) {
|
|
224
|
+
const shallow = { ...component };
|
|
225
|
+
Object.keys(shallow).forEach((key) => {
|
|
226
|
+
if (shallow[key] && typeof shallow[key] === "object") {
|
|
227
|
+
if (shallow[key].children) {
|
|
228
|
+
shallow[key] = {
|
|
229
|
+
...shallow[key],
|
|
230
|
+
children: Array.isArray(shallow[key].children) ? shallow[key].children.map(() => ({ _shallow: true })) : { _shallow: true }
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
return shallow;
|
|
236
|
+
}
|
|
237
|
+
var test_renderer_default = {
|
|
238
|
+
renderComponent,
|
|
239
|
+
renderComponentAsync,
|
|
240
|
+
createTestRenderer,
|
|
241
|
+
shallowRender,
|
|
242
|
+
TestRenderer,
|
|
243
|
+
TestRendererResult
|
|
244
|
+
};
|
|
245
|
+
export {
|
|
246
|
+
TestRenderer,
|
|
247
|
+
TestRendererResult,
|
|
248
|
+
createTestRenderer,
|
|
249
|
+
test_renderer_default as default,
|
|
250
|
+
renderComponent,
|
|
251
|
+
renderComponentAsync,
|
|
252
|
+
shallowRender
|
|
253
|
+
};
|
|
254
|
+
//# sourceMappingURL=test-renderer.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/test-renderer.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * Coherent.js Test Renderer\n * \n * Provides utilities for rendering and testing Coherent.js components\n * in a test environment.\n * \n * @module testing/test-renderer\n */\n\nimport { render } from '@coherent.js/core';\n\n/**\n * Test renderer result\n * Provides methods to query and interact with rendered components\n */\nexport class TestRendererResult {\n constructor(component, html, container = null) {\n this.component = component;\n this.html = html;\n this.container = container;\n this.queries = new Map();\n }\n\n /**\n * Get element by test ID\n * @param {string} testId - Test ID to search for\n * @returns {Object|null} Element or null\n */\n getByTestId(testId) {\n const regex = new RegExp(`data-testid=\"${testId}\"[^>]*>([^<]*)<`, 'i');\n const match = this.html.match(regex);\n \n if (!match) {\n throw new Error(`Unable to find element with testId: ${testId}`);\n }\n \n return {\n text: match[1],\n html: match[0],\n testId,\n exists: true\n };\n }\n\n /**\n * Query element by test ID (returns null if not found)\n * @param {string} testId - Test ID to search for\n * @returns {Object|null} Element or null\n */\n queryByTestId(testId) {\n try {\n return this.getByTestId(testId);\n } catch {\n return null;\n }\n }\n\n /**\n * Get element by text content\n * @param {string|RegExp} text - Text to search for\n * @returns {Object} Element\n */\n getByText(text) {\n const regex = typeof text === 'string' \n ? new RegExp(`>([^<]*${text}[^<]*)<`, 'i')\n : new RegExp(`>([^<]*)<`, 'i');\n \n const match = this.html.match(regex);\n \n if (!match || (typeof text === 'string' && !match[1].includes(text))) {\n throw new Error(`Unable to find element with text: ${text}`);\n }\n \n return {\n text: match[1],\n html: match[0],\n exists: true\n };\n }\n\n /**\n * Query element by text (returns null if not found)\n * @param {string|RegExp} text - Text to search for\n * @returns {Object|null} Element or null\n */\n queryByText(text) {\n try {\n return this.getByText(text);\n } catch {\n return null;\n }\n }\n\n /**\n * Get element by class name\n * @param {string} className - Class name to search for\n * @returns {Object} Element\n */\n getByClassName(className) {\n const regex = new RegExp(`class=\"[^\"]*${className}[^\"]*\"[^>]*>([^<]*)<`, 'i');\n const match = this.html.match(regex);\n \n if (!match) {\n throw new Error(`Unable to find element with className: ${className}`);\n }\n \n return {\n text: match[1],\n html: match[0],\n className,\n exists: true\n };\n }\n\n /**\n * Query element by class name (returns null if not found)\n * @param {string} className - Class name to search for\n * @returns {Object|null} Element or null\n */\n queryByClassName(className) {\n try {\n return this.getByClassName(className);\n } catch {\n return null;\n }\n }\n\n /**\n * Get all elements by tag name\n * @param {string} tagName - Tag name to search for\n * @returns {Array<Object>} Array of elements\n */\n getAllByTagName(tagName) {\n const regex = new RegExp(`<${tagName}[^>]*>([^<]*)</${tagName}>`, 'gi');\n const matches = [...this.html.matchAll(regex)];\n \n return matches.map(match => ({\n text: match[1],\n html: match[0],\n tagName,\n exists: true\n }));\n }\n\n /**\n * Check if element exists\n * @param {string} selector - Selector (testId, text, className)\n * @param {string} type - Type of selector ('testId', 'text', 'className')\n * @returns {boolean} True if exists\n */\n exists(selector, type = 'testId') {\n switch (type) {\n case 'testId':\n return this.queryByTestId(selector) !== null;\n case 'text':\n return this.queryByText(selector) !== null;\n case 'className':\n return this.queryByClassName(selector) !== null;\n default:\n return false;\n }\n }\n\n /**\n * Get the rendered HTML\n * @returns {string} HTML string\n */\n getHTML() {\n return this.html;\n }\n\n /**\n * Get the component\n * @returns {Object} Component object\n */\n getComponent() {\n return this.component;\n }\n\n /**\n * Create a snapshot of the rendered output\n * @returns {string} Formatted HTML for snapshot testing\n */\n toSnapshot() {\n return this.html\n .replace(/>\\s+</g, '><') // Remove whitespace between tags\n .trim();\n }\n\n /**\n * Debug: print the rendered HTML\n */\n debug() {\n console.log('=== Rendered HTML ===');\n console.log(this.html);\n console.log('=== Component ===');\n console.log(JSON.stringify(this.component, null, 2));\n }\n}\n\n/**\n * Render a component for testing\n * \n * @param {Object} component - Component to render\n * @param {Object} [options] - Render options\n * @returns {TestRendererResult} Test renderer result\n * \n * @example\n * const { getByTestId } = renderComponent({\n * div: {\n * 'data-testid': 'my-div',\n * text: 'Hello World'\n * }\n * });\n * \n * expect(getByTestId('my-div').text).toBe('Hello World');\n */\nexport function renderComponent(component, options = {}) {\n const html = render(component, options);\n return new TestRendererResult(component, html);\n}\n\n/**\n * Render a component asynchronously\n * \n * @param {Object|Function} component - Component or component factory\n * @param {Object} [props] - Component props\n * @param {Object} [options] - Render options\n * @returns {Promise<TestRendererResult>} Test renderer result\n */\nexport async function renderComponentAsync(component, props = {}, options = {}) {\n // If component is a function, call it with props\n const resolvedComponent = typeof component === 'function' \n ? await component(props)\n : component;\n \n const html = render(resolvedComponent, options);\n return new TestRendererResult(resolvedComponent, html);\n}\n\n/**\n * Create a test renderer instance\n * Useful for testing component updates\n */\nexport class TestRenderer {\n constructor(component, options = {}) {\n this.component = component;\n this.options = options;\n this.result = null;\n this.renderCount = 0;\n }\n\n /**\n * Render the component\n * @returns {TestRendererResult} Render result\n */\n render() {\n this.renderCount++;\n const html = render(this.component, this.options);\n this.result = new TestRendererResult(this.component, html);\n return this.result;\n }\n\n /**\n * Update the component and re-render\n * @param {Object} newComponent - Updated component\n * @returns {TestRendererResult} Render result\n */\n update(newComponent) {\n this.component = newComponent;\n return this.render();\n }\n\n /**\n * Get the current result\n * @returns {TestRendererResult|null} Current result\n */\n getResult() {\n return this.result;\n }\n\n /**\n * Get render count\n * @returns {number} Number of renders\n */\n getRenderCount() {\n return this.renderCount;\n }\n\n /**\n * Unmount the component\n */\n unmount() {\n this.component = null;\n this.result = null;\n }\n}\n\n/**\n * Create a test renderer\n * \n * @param {Object} component - Component to render\n * @param {Object} [options] - Render options\n * @returns {TestRenderer} Test renderer instance\n * \n * @example\n * const renderer = createTestRenderer(MyComponent);\n * const result = renderer.render();\n * expect(result.getByText('Hello')).toBeTruthy();\n * \n * // Update and re-render\n * renderer.update(UpdatedComponent);\n * expect(renderer.getRenderCount()).toBe(2);\n */\nexport function createTestRenderer(component, options = {}) {\n return new TestRenderer(component, options);\n}\n\n/**\n * Shallow render a component (only render top level)\n * \n * @param {Object} component - Component to render\n * @returns {Object} Shallow rendered component\n */\nexport function shallowRender(component) {\n // Clone component without rendering children\n const shallow = { ...component };\n \n Object.keys(shallow).forEach(key => {\n if (shallow[key] && typeof shallow[key] === 'object') {\n if (shallow[key].children) {\n shallow[key] = {\n ...shallow[key],\n children: Array.isArray(shallow[key].children)\n ? shallow[key].children.map(() => ({ _shallow: true }))\n : { _shallow: true }\n };\n }\n }\n });\n \n return shallow;\n}\n\n/**\n * Export all testing utilities\n */\nexport default {\n renderComponent,\n renderComponentAsync,\n createTestRenderer,\n shallowRender,\n TestRenderer,\n TestRendererResult\n};\n"],
|
|
5
|
+
"mappings": ";AASA,SAAS,cAAc;AAMhB,IAAM,qBAAN,MAAyB;AAAA,EAC9B,YAAY,WAAW,MAAM,YAAY,MAAM;AAC7C,SAAK,YAAY;AACjB,SAAK,OAAO;AACZ,SAAK,YAAY;AACjB,SAAK,UAAU,oBAAI,IAAI;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,QAAQ;AAClB,UAAM,QAAQ,IAAI,OAAO,gBAAgB,MAAM,mBAAmB,GAAG;AACrE,UAAM,QAAQ,KAAK,KAAK,MAAM,KAAK;AAEnC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,uCAAuC,MAAM,EAAE;AAAA,IACjE;AAEA,WAAO;AAAA,MACL,MAAM,MAAM,CAAC;AAAA,MACb,MAAM,MAAM,CAAC;AAAA,MACb;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAc,QAAQ;AACpB,QAAI;AACF,aAAO,KAAK,YAAY,MAAM;AAAA,IAChC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU,MAAM;AACd,UAAM,QAAQ,OAAO,SAAS,WAC1B,IAAI,OAAO,UAAU,IAAI,WAAW,GAAG,IACvC,IAAI,OAAO,aAAa,GAAG;AAE/B,UAAM,QAAQ,KAAK,KAAK,MAAM,KAAK;AAEnC,QAAI,CAAC,SAAU,OAAO,SAAS,YAAY,CAAC,MAAM,CAAC,EAAE,SAAS,IAAI,GAAI;AACpE,YAAM,IAAI,MAAM,qCAAqC,IAAI,EAAE;AAAA,IAC7D;AAEA,WAAO;AAAA,MACL,MAAM,MAAM,CAAC;AAAA,MACb,MAAM,MAAM,CAAC;AAAA,MACb,QAAQ;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,MAAM;AAChB,QAAI;AACF,aAAO,KAAK,UAAU,IAAI;AAAA,IAC5B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe,WAAW;AACxB,UAAM,QAAQ,IAAI,OAAO,eAAe,SAAS,wBAAwB,GAAG;AAC5E,UAAM,QAAQ,KAAK,KAAK,MAAM,KAAK;AAEnC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,0CAA0C,SAAS,EAAE;AAAA,IACvE;AAEA,WAAO;AAAA,MACL,MAAM,MAAM,CAAC;AAAA,MACb,MAAM,MAAM,CAAC;AAAA,MACb;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAiB,WAAW;AAC1B,QAAI;AACF,aAAO,KAAK,eAAe,SAAS;AAAA,IACtC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAgB,SAAS;AACvB,UAAM,QAAQ,IAAI,OAAO,IAAI,OAAO,kBAAkB,OAAO,KAAK,IAAI;AACtE,UAAM,UAAU,CAAC,GAAG,KAAK,KAAK,SAAS,KAAK,CAAC;AAE7C,WAAO,QAAQ,IAAI,YAAU;AAAA,MAC3B,MAAM,MAAM,CAAC;AAAA,MACb,MAAM,MAAM,CAAC;AAAA,MACb;AAAA,MACA,QAAQ;AAAA,IACV,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,UAAU,OAAO,UAAU;AAChC,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,eAAO,KAAK,cAAc,QAAQ,MAAM;AAAA,MAC1C,KAAK;AACH,eAAO,KAAK,YAAY,QAAQ,MAAM;AAAA,MACxC,KAAK;AACH,eAAO,KAAK,iBAAiB,QAAQ,MAAM;AAAA,MAC7C;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU;AACR,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAe;AACb,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa;AACX,WAAO,KAAK,KACT,QAAQ,UAAU,IAAI,EACtB,KAAK;AAAA,EACV;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ;AACN,YAAQ,IAAI,uBAAuB;AACnC,YAAQ,IAAI,KAAK,IAAI;AACrB,YAAQ,IAAI,mBAAmB;AAC/B,YAAQ,IAAI,KAAK,UAAU,KAAK,WAAW,MAAM,CAAC,CAAC;AAAA,EACrD;AACF;AAmBO,SAAS,gBAAgB,WAAW,UAAU,CAAC,GAAG;AACvD,QAAM,OAAO,OAAO,WAAW,OAAO;AACtC,SAAO,IAAI,mBAAmB,WAAW,IAAI;AAC/C;AAUA,eAAsB,qBAAqB,WAAW,QAAQ,CAAC,GAAG,UAAU,CAAC,GAAG;AAE9E,QAAM,oBAAoB,OAAO,cAAc,aAC3C,MAAM,UAAU,KAAK,IACrB;AAEJ,QAAM,OAAO,OAAO,mBAAmB,OAAO;AAC9C,SAAO,IAAI,mBAAmB,mBAAmB,IAAI;AACvD;AAMO,IAAM,eAAN,MAAmB;AAAA,EACxB,YAAY,WAAW,UAAU,CAAC,GAAG;AACnC,SAAK,YAAY;AACjB,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS;AACP,SAAK;AACL,UAAM,OAAO,OAAO,KAAK,WAAW,KAAK,OAAO;AAChD,SAAK,SAAS,IAAI,mBAAmB,KAAK,WAAW,IAAI;AACzD,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,cAAc;AACnB,SAAK,YAAY;AACjB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY;AACV,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB;AACf,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACR,SAAK,YAAY;AACjB,SAAK,SAAS;AAAA,EAChB;AACF;AAkBO,SAAS,mBAAmB,WAAW,UAAU,CAAC,GAAG;AAC1D,SAAO,IAAI,aAAa,WAAW,OAAO;AAC5C;AAQO,SAAS,cAAc,WAAW;AAEvC,QAAM,UAAU,EAAE,GAAG,UAAU;AAE/B,SAAO,KAAK,OAAO,EAAE,QAAQ,SAAO;AAClC,QAAI,QAAQ,GAAG,KAAK,OAAO,QAAQ,GAAG,MAAM,UAAU;AACpD,UAAI,QAAQ,GAAG,EAAE,UAAU;AACzB,gBAAQ,GAAG,IAAI;AAAA,UACb,GAAG,QAAQ,GAAG;AAAA,UACd,UAAU,MAAM,QAAQ,QAAQ,GAAG,EAAE,QAAQ,IACzC,QAAQ,GAAG,EAAE,SAAS,IAAI,OAAO,EAAE,UAAU,KAAK,EAAE,IACpD,EAAE,UAAU,KAAK;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAKA,IAAO,wBAAQ;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
// src/test-utils.js
|
|
2
|
+
function fireEvent(element, eventType, eventData = {}) {
|
|
3
|
+
if (!element) {
|
|
4
|
+
throw new Error("Element is required for fireEvent");
|
|
5
|
+
}
|
|
6
|
+
const event = {
|
|
7
|
+
type: eventType,
|
|
8
|
+
target: element,
|
|
9
|
+
currentTarget: element,
|
|
10
|
+
preventDefault: () => {
|
|
11
|
+
},
|
|
12
|
+
stopPropagation: () => {
|
|
13
|
+
},
|
|
14
|
+
...eventData
|
|
15
|
+
};
|
|
16
|
+
const handlerName = `on${eventType}`;
|
|
17
|
+
if (element[handlerName] && typeof element[handlerName] === "function") {
|
|
18
|
+
element[handlerName](event);
|
|
19
|
+
}
|
|
20
|
+
return event;
|
|
21
|
+
}
|
|
22
|
+
var fireEvent_click = (element, eventData) => fireEvent(element, "click", eventData);
|
|
23
|
+
var fireEvent_change = (element, value) => fireEvent(element, "change", { target: { value } });
|
|
24
|
+
var fireEvent_input = (element, value) => fireEvent(element, "input", { target: { value } });
|
|
25
|
+
var fireEvent_submit = (element, eventData) => fireEvent(element, "submit", eventData);
|
|
26
|
+
var fireEvent_keyDown = (element, key) => fireEvent(element, "keydown", { key });
|
|
27
|
+
var fireEvent_keyUp = (element, key) => fireEvent(element, "keyup", { key });
|
|
28
|
+
var fireEvent_focus = (element) => fireEvent(element, "focus");
|
|
29
|
+
var fireEvent_blur = (element) => fireEvent(element, "blur");
|
|
30
|
+
function waitFor(condition, options = {}) {
|
|
31
|
+
const { timeout = 1e3, interval = 50 } = options;
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const startTime = Date.now();
|
|
34
|
+
const check = () => {
|
|
35
|
+
try {
|
|
36
|
+
if (condition()) {
|
|
37
|
+
resolve();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
if (Date.now() - startTime >= timeout) {
|
|
43
|
+
reject(new Error(`Timeout waiting for condition after ${timeout}ms`));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
setTimeout(check, interval);
|
|
47
|
+
};
|
|
48
|
+
check();
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async function waitForElement(queryFn, options = {}) {
|
|
52
|
+
let element = null;
|
|
53
|
+
await waitFor(() => {
|
|
54
|
+
element = queryFn();
|
|
55
|
+
return element !== null;
|
|
56
|
+
}, options);
|
|
57
|
+
return element;
|
|
58
|
+
}
|
|
59
|
+
async function waitForElementToBeRemoved(queryFn, options = {}) {
|
|
60
|
+
await waitFor(() => {
|
|
61
|
+
const element = queryFn();
|
|
62
|
+
return element === null;
|
|
63
|
+
}, options);
|
|
64
|
+
}
|
|
65
|
+
async function act(callback) {
|
|
66
|
+
await callback();
|
|
67
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
68
|
+
}
|
|
69
|
+
function createMock(implementation) {
|
|
70
|
+
const calls = [];
|
|
71
|
+
const results = [];
|
|
72
|
+
const mockFn = function(...args) {
|
|
73
|
+
calls.push(args);
|
|
74
|
+
let result;
|
|
75
|
+
let error;
|
|
76
|
+
try {
|
|
77
|
+
result = implementation ? implementation(...args) : void 0;
|
|
78
|
+
results.push({ type: "return", value: result });
|
|
79
|
+
} catch (err) {
|
|
80
|
+
error = err;
|
|
81
|
+
results.push({ type: "throw", value: error });
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
};
|
|
86
|
+
mockFn.mock = {
|
|
87
|
+
calls,
|
|
88
|
+
results,
|
|
89
|
+
instances: []
|
|
90
|
+
};
|
|
91
|
+
mockFn.mockClear = () => {
|
|
92
|
+
calls.length = 0;
|
|
93
|
+
results.length = 0;
|
|
94
|
+
};
|
|
95
|
+
mockFn.mockReset = () => {
|
|
96
|
+
mockFn.mockClear();
|
|
97
|
+
implementation = void 0;
|
|
98
|
+
};
|
|
99
|
+
mockFn.mockImplementation = (fn) => {
|
|
100
|
+
implementation = fn;
|
|
101
|
+
return mockFn;
|
|
102
|
+
};
|
|
103
|
+
mockFn.mockReturnValue = (value) => {
|
|
104
|
+
implementation = () => value;
|
|
105
|
+
return mockFn;
|
|
106
|
+
};
|
|
107
|
+
mockFn.mockResolvedValue = (value) => {
|
|
108
|
+
implementation = () => Promise.resolve(value);
|
|
109
|
+
return mockFn;
|
|
110
|
+
};
|
|
111
|
+
mockFn.mockRejectedValue = (error) => {
|
|
112
|
+
implementation = () => Promise.reject(error);
|
|
113
|
+
return mockFn;
|
|
114
|
+
};
|
|
115
|
+
return mockFn;
|
|
116
|
+
}
|
|
117
|
+
function createSpy(object, method) {
|
|
118
|
+
const original = object[method];
|
|
119
|
+
const spy = createMock(original.bind(object));
|
|
120
|
+
object[method] = spy;
|
|
121
|
+
spy.mockRestore = () => {
|
|
122
|
+
object[method] = original;
|
|
123
|
+
};
|
|
124
|
+
return spy;
|
|
125
|
+
}
|
|
126
|
+
function cleanup() {
|
|
127
|
+
}
|
|
128
|
+
function within(container) {
|
|
129
|
+
return {
|
|
130
|
+
getByTestId: (testId) => container.getByTestId(testId),
|
|
131
|
+
queryByTestId: (testId) => container.queryByTestId(testId),
|
|
132
|
+
getByText: (text) => container.getByText(text),
|
|
133
|
+
queryByText: (text) => container.queryByText(text),
|
|
134
|
+
getByClassName: (className) => container.getByClassName(className),
|
|
135
|
+
queryByClassName: (className) => container.queryByClassName(className)
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
var screen = {
|
|
139
|
+
_result: null,
|
|
140
|
+
setResult(result) {
|
|
141
|
+
this._result = result;
|
|
142
|
+
},
|
|
143
|
+
getByTestId(testId) {
|
|
144
|
+
if (!this._result) throw new Error("No component rendered");
|
|
145
|
+
return this._result.getByTestId(testId);
|
|
146
|
+
},
|
|
147
|
+
queryByTestId(testId) {
|
|
148
|
+
if (!this._result) return null;
|
|
149
|
+
return this._result.queryByTestId(testId);
|
|
150
|
+
},
|
|
151
|
+
getByText(text) {
|
|
152
|
+
if (!this._result) throw new Error("No component rendered");
|
|
153
|
+
return this._result.getByText(text);
|
|
154
|
+
},
|
|
155
|
+
queryByText(text) {
|
|
156
|
+
if (!this._result) return null;
|
|
157
|
+
return this._result.queryByText(text);
|
|
158
|
+
},
|
|
159
|
+
getByClassName(className) {
|
|
160
|
+
if (!this._result) throw new Error("No component rendered");
|
|
161
|
+
return this._result.getByClassName(className);
|
|
162
|
+
},
|
|
163
|
+
queryByClassName(className) {
|
|
164
|
+
if (!this._result) return null;
|
|
165
|
+
return this._result.queryByClassName(className);
|
|
166
|
+
},
|
|
167
|
+
debug() {
|
|
168
|
+
if (this._result) {
|
|
169
|
+
this._result.debug();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
var userEvent = {
|
|
174
|
+
/**
|
|
175
|
+
* Simulate user typing
|
|
176
|
+
*/
|
|
177
|
+
type: async (element, text, options = {}) => {
|
|
178
|
+
const { delay = 0 } = options;
|
|
179
|
+
for (const char of text) {
|
|
180
|
+
fireEvent_keyDown(element, char);
|
|
181
|
+
fireEvent_input(element, element.value + char);
|
|
182
|
+
fireEvent_keyUp(element, char);
|
|
183
|
+
if (delay > 0) {
|
|
184
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
/**
|
|
189
|
+
* Simulate user click
|
|
190
|
+
*/
|
|
191
|
+
click: async (element) => {
|
|
192
|
+
fireEvent_focus(element);
|
|
193
|
+
fireEvent_click(element);
|
|
194
|
+
},
|
|
195
|
+
/**
|
|
196
|
+
* Simulate user double click
|
|
197
|
+
*/
|
|
198
|
+
dblClick: async (element) => {
|
|
199
|
+
await userEvent.click(element);
|
|
200
|
+
await userEvent.click(element);
|
|
201
|
+
},
|
|
202
|
+
/**
|
|
203
|
+
* Simulate user clearing input
|
|
204
|
+
*/
|
|
205
|
+
clear: async (element) => {
|
|
206
|
+
fireEvent_input(element, "");
|
|
207
|
+
fireEvent_change(element, "");
|
|
208
|
+
},
|
|
209
|
+
/**
|
|
210
|
+
* Simulate user selecting option
|
|
211
|
+
*/
|
|
212
|
+
selectOptions: async (element, values) => {
|
|
213
|
+
const valueArray = Array.isArray(values) ? values : [values];
|
|
214
|
+
fireEvent_change(element, valueArray[0]);
|
|
215
|
+
},
|
|
216
|
+
/**
|
|
217
|
+
* Simulate user tab navigation
|
|
218
|
+
*/
|
|
219
|
+
tab: async () => {
|
|
220
|
+
const activeElement = document.activeElement;
|
|
221
|
+
if (activeElement) {
|
|
222
|
+
fireEvent_keyDown(activeElement, "Tab");
|
|
223
|
+
fireEvent_blur(activeElement);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
var test_utils_default = {
|
|
228
|
+
fireEvent,
|
|
229
|
+
waitFor,
|
|
230
|
+
waitForElement,
|
|
231
|
+
waitForElementToBeRemoved,
|
|
232
|
+
act,
|
|
233
|
+
createMock,
|
|
234
|
+
createSpy,
|
|
235
|
+
cleanup,
|
|
236
|
+
within,
|
|
237
|
+
screen,
|
|
238
|
+
userEvent
|
|
239
|
+
};
|
|
240
|
+
export {
|
|
241
|
+
act,
|
|
242
|
+
cleanup,
|
|
243
|
+
createMock,
|
|
244
|
+
createSpy,
|
|
245
|
+
test_utils_default as default,
|
|
246
|
+
fireEvent,
|
|
247
|
+
fireEvent_blur,
|
|
248
|
+
fireEvent_change,
|
|
249
|
+
fireEvent_click,
|
|
250
|
+
fireEvent_focus,
|
|
251
|
+
fireEvent_input,
|
|
252
|
+
fireEvent_keyDown,
|
|
253
|
+
fireEvent_keyUp,
|
|
254
|
+
fireEvent_submit,
|
|
255
|
+
screen,
|
|
256
|
+
userEvent,
|
|
257
|
+
waitFor,
|
|
258
|
+
waitForElement,
|
|
259
|
+
waitForElementToBeRemoved,
|
|
260
|
+
within
|
|
261
|
+
};
|
|
262
|
+
//# sourceMappingURL=test-utils.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/test-utils.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * Coherent.js Test Utilities\n * \n * Helper functions for testing Coherent.js components\n * \n * @module testing/test-utils\n */\n\n/**\n * Simulate an event on an element\n * \n * @param {Object} element - Element to fire event on\n * @param {string} eventType - Type of event (click, change, etc.)\n * @param {Object} [eventData] - Additional event data\n */\nexport function fireEvent(element, eventType, eventData = {}) {\n if (!element) {\n throw new Error('Element is required for fireEvent');\n }\n \n // In a test environment, we simulate the event\n const event = {\n type: eventType,\n target: element,\n currentTarget: element,\n preventDefault: () => {},\n stopPropagation: () => {},\n ...eventData\n };\n \n // If element has an event handler, call it\n const handlerName = `on${eventType}`;\n if (element[handlerName] && typeof element[handlerName] === 'function') {\n element[handlerName](event);\n }\n \n return event;\n}\n\n/**\n * Common event helpers\n */\nexport const fireEvent_click = (element, eventData) => \n fireEvent(element, 'click', eventData);\n\nexport const fireEvent_change = (element, value) => \n fireEvent(element, 'change', { target: { value } });\n\nexport const fireEvent_input = (element, value) => \n fireEvent(element, 'input', { target: { value } });\n\nexport const fireEvent_submit = (element, eventData) => \n fireEvent(element, 'submit', eventData);\n\nexport const fireEvent_keyDown = (element, key) => \n fireEvent(element, 'keydown', { key });\n\nexport const fireEvent_keyUp = (element, key) => \n fireEvent(element, 'keyup', { key });\n\nexport const fireEvent_focus = (element) => \n fireEvent(element, 'focus');\n\nexport const fireEvent_blur = (element) => \n fireEvent(element, 'blur');\n\n/**\n * Wait for a condition to be true\n * \n * @param {Function} condition - Condition function\n * @param {Object} [options] - Wait options\n * @param {number} [options.timeout=1000] - Timeout in ms\n * @param {number} [options.interval=50] - Check interval in ms\n * @returns {Promise<void>}\n * \n * @example\n * await waitFor(() => getByText('Loaded').exists, { timeout: 2000 });\n */\nexport function waitFor(condition, options = {}) {\n const { timeout = 1000, interval = 50 } = options;\n \n return new Promise((resolve, reject) => {\n const startTime = Date.now();\n \n const check = () => {\n try {\n if (condition()) {\n resolve();\n return;\n }\n } catch {\n // Condition threw an error, keep waiting\n }\n \n if (Date.now() - startTime >= timeout) {\n reject(new Error(`Timeout waiting for condition after ${timeout}ms`));\n return;\n }\n \n setTimeout(check, interval);\n };\n \n check();\n });\n}\n\n/**\n * Wait for element to appear\n * \n * @param {Function} queryFn - Query function that returns element\n * @param {Object} [options] - Wait options\n * @returns {Promise<Object>} Element\n */\nexport async function waitForElement(queryFn, options = {}) {\n let element = null;\n \n await waitFor(() => {\n element = queryFn();\n return element !== null;\n }, options);\n \n return element;\n}\n\n/**\n * Wait for element to disappear\n * \n * @param {Function} queryFn - Query function that returns element\n * @param {Object} [options] - Wait options\n * @returns {Promise<void>}\n */\nexport async function waitForElementToBeRemoved(queryFn, options = {}) {\n await waitFor(() => {\n const element = queryFn();\n return element === null;\n }, options);\n}\n\n/**\n * Act utility for batching updates\n * Useful for testing state changes\n * \n * @param {Function} callback - Callback to execute\n * @returns {Promise<void>}\n */\nexport async function act(callback) {\n await callback();\n // Allow any pending updates to flush\n await new Promise(resolve => setTimeout(resolve, 0));\n}\n\n/**\n * Create a mock function\n * \n * @param {Function} [implementation] - Optional implementation\n * @returns {Function} Mock function\n */\nexport function createMock(implementation) {\n const calls = [];\n const results = [];\n \n const mockFn = function(...args) {\n calls.push(args);\n \n let result;\n let error;\n \n try {\n result = implementation ? implementation(...args) : undefined;\n results.push({ type: 'return', value: result });\n } catch (err) {\n error = err;\n results.push({ type: 'throw', value: error });\n throw error;\n }\n \n return result;\n };\n \n // Add mock utilities\n mockFn.mock = {\n calls,\n results,\n instances: []\n };\n \n mockFn.mockClear = () => {\n calls.length = 0;\n results.length = 0;\n };\n \n mockFn.mockReset = () => {\n mockFn.mockClear();\n implementation = undefined;\n };\n \n mockFn.mockImplementation = (fn) => {\n implementation = fn;\n return mockFn;\n };\n \n mockFn.mockReturnValue = (value) => {\n implementation = () => value;\n return mockFn;\n };\n \n mockFn.mockResolvedValue = (value) => {\n implementation = () => Promise.resolve(value);\n return mockFn;\n };\n \n mockFn.mockRejectedValue = (error) => {\n implementation = () => Promise.reject(error);\n return mockFn;\n };\n \n return mockFn;\n}\n\n/**\n * Create a spy on an object method\n * \n * @param {Object} object - Object to spy on\n * @param {string} method - Method name\n * @returns {Function} Spy function\n */\nexport function createSpy(object, method) {\n const original = object[method];\n const spy = createMock(original.bind(object));\n \n object[method] = spy;\n \n spy.mockRestore = () => {\n object[method] = original;\n };\n \n return spy;\n}\n\n/**\n * Cleanup utility\n * Cleans up after tests\n */\nexport function cleanup() {\n // Clear any timers\n // Reset any global state\n // This would be expanded based on framework needs\n}\n\n/**\n * Within utility - scopes queries to a container\n * \n * @param {Object} container - Container result\n * @returns {Object} Scoped queries\n */\nexport function within(container) {\n return {\n getByTestId: (testId) => container.getByTestId(testId),\n queryByTestId: (testId) => container.queryByTestId(testId),\n getByText: (text) => container.getByText(text),\n queryByText: (text) => container.queryByText(text),\n getByClassName: (className) => container.getByClassName(className),\n queryByClassName: (className) => container.queryByClassName(className)\n };\n}\n\n/**\n * Screen utility - global queries\n * Useful for accessing rendered content without storing result\n */\nexport const screen = {\n _result: null,\n \n setResult(result) {\n this._result = result;\n },\n \n getByTestId(testId) {\n if (!this._result) throw new Error('No component rendered');\n return this._result.getByTestId(testId);\n },\n \n queryByTestId(testId) {\n if (!this._result) return null;\n return this._result.queryByTestId(testId);\n },\n \n getByText(text) {\n if (!this._result) throw new Error('No component rendered');\n return this._result.getByText(text);\n },\n \n queryByText(text) {\n if (!this._result) return null;\n return this._result.queryByText(text);\n },\n \n getByClassName(className) {\n if (!this._result) throw new Error('No component rendered');\n return this._result.getByClassName(className);\n },\n \n queryByClassName(className) {\n if (!this._result) return null;\n return this._result.queryByClassName(className);\n },\n \n debug() {\n if (this._result) {\n this._result.debug();\n }\n }\n};\n\n/**\n * User event simulation\n * More realistic event simulation than fireEvent\n */\nexport const userEvent = {\n /**\n * Simulate user typing\n */\n type: async (element, text, options = {}) => {\n const { delay = 0 } = options;\n \n for (const char of text) {\n fireEvent_keyDown(element, char);\n fireEvent_input(element, element.value + char);\n fireEvent_keyUp(element, char);\n \n if (delay > 0) {\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n },\n \n /**\n * Simulate user click\n */\n click: async (element) => {\n fireEvent_focus(element);\n fireEvent_click(element);\n },\n \n /**\n * Simulate user double click\n */\n dblClick: async (element) => {\n await userEvent.click(element);\n await userEvent.click(element);\n },\n \n /**\n * Simulate user clearing input\n */\n clear: async (element) => {\n fireEvent_input(element, '');\n fireEvent_change(element, '');\n },\n \n /**\n * Simulate user selecting option\n */\n selectOptions: async (element, values) => {\n const valueArray = Array.isArray(values) ? values : [values];\n fireEvent_change(element, valueArray[0]);\n },\n \n /**\n * Simulate user tab navigation\n */\n tab: async () => {\n // Simulate tab key\n const activeElement = document.activeElement;\n if (activeElement) {\n fireEvent_keyDown(activeElement, 'Tab');\n fireEvent_blur(activeElement);\n }\n }\n};\n\n/**\n * Export all utilities\n */\nexport default {\n fireEvent,\n waitFor,\n waitForElement,\n waitForElementToBeRemoved,\n act,\n createMock,\n createSpy,\n cleanup,\n within,\n screen,\n userEvent\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coherent.js/testing",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.7",
|
|
4
4
|
"description": "Testing utilities for Coherent.js applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"author": "Coherent.js Team",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"peerDependencies": {
|
|
22
|
-
"@coherent.js/core": "1.0.0-beta.
|
|
22
|
+
"@coherent.js/core": "1.0.0-beta.7"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"vitest": "^1.0.0"
|
|
@@ -28,11 +28,19 @@
|
|
|
28
28
|
"type": "git",
|
|
29
29
|
"url": "git+https://github.com/Tomdrouv1/coherent.js.git"
|
|
30
30
|
},
|
|
31
|
+
"homepage": "https://github.com/Tomdrouv1/coherent.js",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/Tomdrouv1/coherent.js/issues"
|
|
34
|
+
},
|
|
31
35
|
"publishConfig": {
|
|
32
36
|
"access": "public"
|
|
33
37
|
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20.0.0"
|
|
40
|
+
},
|
|
34
41
|
"types": "./types/index.d.ts",
|
|
35
42
|
"files": [
|
|
43
|
+
"dist/",
|
|
36
44
|
"LICENSE",
|
|
37
45
|
"README.md",
|
|
38
46
|
"types/"
|