diff --git a/packages/expect-puppeteer/README.md b/packages/expect-puppeteer/README.md index d303c91e..aa7ee02d 100644 --- a/packages/expect-puppeteer/README.md +++ b/packages/expect-puppeteer/README.md @@ -85,7 +85,7 @@ Expect an element to be in the page or element, then click on it. * `raf` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes. * `mutation` - to execute `pageFunction` on every DOM mutation. * `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `500`. - * `text` <[string]> A text or a RegExp to match in element `textContent`. + * `text` <[string]|[RegExp]> A text or a RegExp to match in element `textContent`. ```js await expect(page).toClick('button', { text: 'Home' }) @@ -172,7 +172,7 @@ Expect an element be present in the page or element. * `raf` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes. * `mutation` - to execute `pageFunction` on every DOM mutation. * `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `500`. - * `text` <[string]> A text or a RegExp to match in element `textContent`. + * `text` <[string]|[RegExp]> A text or a RegExp to match in element `textContent`. ```js // Select a row containing a text @@ -246,6 +246,7 @@ MIT [number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type 'Number' [object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 'Object' [promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 'Promise' +[regexp]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp 'RegExp' [string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type 'String' [error]: https://nodejs.org/api/errors.html#errors_class_error 'Error' [element]: https://developer.mozilla.org/en-US/docs/Web/API/element 'Element' diff --git a/packages/expect-puppeteer/src/matchers/toMatchElement.js b/packages/expect-puppeteer/src/matchers/toMatchElement.js index 48008032..4e0e6cf5 100644 --- a/packages/expect-puppeteer/src/matchers/toMatchElement.js +++ b/packages/expect-puppeteer/src/matchers/toMatchElement.js @@ -1,31 +1,73 @@ import { getContext, enhanceError } from '../utils' import { defaultOptions } from '../options' -async function toMatchElement(instance, selector, { text, ...options } = {}) { +const isRegExp = input => + Object.prototype.toString.call(input) === '[object RegExp]' + +const expandSearchExpr = expr => { + if (isRegExp(expr)) return { text: null, regexp: expr.toString() } + if (typeof expr === 'string') return { text: expr, regexp: null } + return { text: null, regexp: null } +} + +async function toMatchElement( + instance, + selector, + { text: searchExpr, ...options } = {}, +) { options = defaultOptions(options) const { page, handle } = await getContext(instance, () => document) - const getElement = (handle, selector, text) => { + const { text, regexp } = expandSearchExpr(searchExpr) + + const getElement = (handle, selector, text, regexp) => { const elements = handle.querySelectorAll(selector) - if (text !== undefined) { - return [...elements].find(({ textContent }) => textContent.match(text)) + if (regexp !== null) { + const [, pattern, flags] = regexp.match(/\/(.*)\/(.*)?/) + return [...elements].find(({ textContent }) => + textContent + .replace(/\s+/g, ' ') + .trim() + .match(new RegExp(pattern, flags)), + ) + } + if (text !== null) { + return [...elements].find(({ textContent }) => + textContent + .replace(/\s+/g, ' ') + .trim() + .includes(text), + ) } return elements[0] } try { - await page.waitForFunction(getElement, options, handle, selector, text) + await page.waitForFunction( + getElement, + options, + handle, + selector, + text, + regexp, + ) } catch (error) { throw enhanceError( error, `Element ${selector}${ - text !== undefined ? ` (text: "${text}") ` : ' ' + text !== null || regexp !== null ? ` (text: "${text || regexp}") ` : ' ' }not found`, ) } - const jsHandle = await page.evaluateHandle(getElement, handle, selector, text) + const jsHandle = await page.evaluateHandle( + getElement, + handle, + selector, + text, + regexp, + ) return jsHandle.asElement() } diff --git a/packages/expect-puppeteer/src/matchers/toMatchElement.test.js b/packages/expect-puppeteer/src/matchers/toMatchElement.test.js index ff9f4159..9cd0962e 100644 --- a/packages/expect-puppeteer/src/matchers/toMatchElement.test.js +++ b/packages/expect-puppeteer/src/matchers/toMatchElement.test.js @@ -11,13 +11,22 @@ describe('toMatchElement', () => { expect(textContent).toBe('Page 2') }) - it('should match using text', async () => { + it('should match using text (string)', async () => { const element = await expect(page).toMatchElement('a', { text: 'Page 2' }) const textContentProperty = await element.getProperty('textContent') const textContent = await textContentProperty.jsonValue() expect(textContent).toBe('Page 2') }) + it('should match using text (RegExp)', async () => { + const element = await expect(page).toMatchElement('a', { + text: /Page\s2/, + }) + const textContentProperty = await element.getProperty('textContent') + const textContent = await textContentProperty.jsonValue() + expect(textContent).toBe('Page 2') + }) + it('should return an error if element is not found', async () => { expect.assertions(3) @@ -39,7 +48,7 @@ describe('toMatchElement', () => { expect(textContent).toMatch('A div in the main') }) - it('should match using text', async () => { + it('should match using text (string)', async () => { const main = await page.$('main') const element = await expect(main).toMatchElement('*', { text: 'in the main', @@ -49,6 +58,16 @@ describe('toMatchElement', () => { expect(textContent).toMatch('A div in the main') }) + it('should match using text (RegExp)', async () => { + const main = await page.$('main') + const element = await expect(main).toMatchElement('*', { + text: /in.the\smain/g, + }) + const textContentProperty = await element.getProperty('textContent') + const textContent = await textContentProperty.jsonValue() + expect(textContent).toMatch('A div in the main') + }) + it('should return an error if element is not found', async () => { const main = await page.$('main') expect.assertions(3)