Repository: kentcdodds/dom-testing-library
Pull request #1 (2018-04-06 14:07:31)

Refactor custom matchers
(re-creating https://github.com/kentcdodds/react-testing-library/pull/46)

This is a proposed refactor to the custom matchers code, as briefly discussed in https://github.com/kentcdodds/react-testing-library/pull/44#discussion_r179593891:

- [x] Use common message format across all custom matchers
- [x] Make it easy to adopt the same format in any future matchers
- [x] Simplify code, remove unneeded if/else logic

Closes #45

#### Proposed changes not yet performed (pending discussion)

- [ ] Make each custom matcher a named export, instead of bundling them in an object as default export
- [ ] Better organize in a sub folder with one file per matchers and some utils file for common stuff

#### Pending to be fixed

- [x] Code coverage is not full because `getDisplayName` never gets called during the tests with a class as argument, only with html elements. I wonder if that is expected, given that this library is only dealing with rendered html and not the virtual dom, or is it?

codecov[bot]: # [Codecov](https://codecov.io/gh/kentcdodds/dom-testing-library/pull/1?src=pr&el=h1) Report
> Merging [#1](https://codecov.io/gh/kentcdodds/dom-testing-library/pull/1?src=pr&el=desc) into [master](https://codecov.io/gh/kentcdodds/dom-testing-library/commit/f19e2761f0a50a1c0fc8a2347ecf2ba07ff5f3f1?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/kentcdodds/dom-testing-library/pull/1/graphs/tree.svg?src=pr&width=650&token=SJPvF6l5rp&height=150)](https://codecov.io/gh/kentcdodds/dom-testing-library/pull/1?src=pr&el=tree)

```diff
@@          Coverage Diff          @@
##           master     #1   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           5      5           
  Lines          91     85    -6     
  Branches       22     24    +2     
=====================================
- Hits           91     85    -6
```


| [Impacted Files](https://codecov.io/gh/kentcdodds/dom-testing-library/pull/1?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/jest-extensions.js](https://codecov.io/gh/kentcdodds/dom-testing-library/pull/1/diff?src=pr&el=tree#diff-c3JjL2plc3QtZXh0ZW5zaW9ucy5qcw==) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/kentcdodds/dom-testing-library/pull/1?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/kentcdodds/dom-testing-library/pull/1?src=pr&el=footer). Last update [f19e276...e141566](https://codecov.io/gh/kentcdodds/dom-testing-library/pull/1?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/src/jest-extensions.js b/src/jest-extensions.js
index 5dd7cb2..228a40e 100644
--- a/src/jest-extensions.js
+++ b/src/jest-extensions.js
@@ -1,6 +1,5 @@
 import {
   matcherHint,
-  printReceived,
   printExpected,
   stringify,
   RECEIVED_COLOR as receivedColor,
@@ -26,9 +25,19 @@ function checkHtmlElement(htmlElement) {
   }
 }
 
-const assertMessage = (assertionName, message, received, expected) =>
-  `${matcherHint(`${assertionName}`, 'received', '')} \n${message}: ` +
-  `${printExpected(expected)} \nReceived: ${printReceived(received)}`
+function getMessage(
+  matcher,
+  expectedLabel,
+  expectedValue,
+  receivedLabel,
+  receivedValue,
+) {
+  return [
+    `${matcher}\n`,
+    `${expectedLabel}:\n  ${expectedColor(expectedValue)}`,
+    `${receivedLabel}:\n  ${receivedColor(receivedValue)}`,
+  ].join('\n')
+}
 
 function printAttribute(name, value) {
   return value === undefined ? name : `${name}=${stringify(value)}`
@@ -42,58 +51,47 @@ function getAttributeComment(name, value) {
 
 const extensions = {
   toBeInTheDOM(received) {
-    getDisplayName(received)
     if (received) {
-      return {
-        message: () =>
-          `${matcherHint(
-            '.not.toBeInTheDOM',
-            'received',
-            '',
-          )} Expected the element not to be present` +
-          `\nReceived : ${printReceived(received)}`,
-        pass: true,
-      }
-    } else {
-      return {
-        message: () =>
-          `${matcherHint(
-            '.toBeInTheDOM',
-            'received',
+      checkHtmlElement(received)
+    }
+    return {
+      pass: !!received,
+      message: () => {
+        const to = this.isNot ? 'not to' : 'to'
+        return getMessage(
+          matcherHint(
+            `${this.isNot ? '.not' : ''}.toBeInTheDOM`,
+            'element',
             '',
-          )} Expected the element to be present` +
-          `\nReceived : ${printReceived(received)}`,
-        pass: false,
-      }
+          ),
+          'Expected',
+          `element ${to} be present`,
+          'Received',
+          received,
+        )
+      },
     }
   },
 
   toHaveTextContent(htmlElement, checkWith) {
     checkHtmlElement(htmlElement)
     const textContent = htmlElement.textContent
-    const pass = matches(textContent, htmlElement, checkWith)
-    if (pass) {
-      return {
-        message: () =>
-          assertMessage(
-            '.not.toHaveTextContent',
-            'Expected value not equals to',
-            htmlElement,
-            checkWith,
-          ),
-        pass: true,
-      }
-    } else {
-      return {
-        message: () =>
-          assertMessage(
-            '.toHaveTextContent',
-            'Expected value equals to',
-            htmlElement,
-            checkWith,
+    return {
+      pass: matches(textContent, htmlElement, checkWith),
+      message: () => {
+        const to = this.isNot ? 'not to' : 'to'
+        return getMessage(
+          matcherHint(
+            `${this.isNot ? '.not' : ''}.toHaveTextContent`,
+            'element',
+            '',
           ),
-        pass: false,
-      }
+          `Expected element ${to} have text content`,
+          checkWith,
+          'Received',
+          textContent,
+        )
+      },
     }
   },
 
@@ -108,14 +106,9 @@ const extensions = {
         : hasAttribute,
       message: () => {
         const to = this.isNot ? 'not to' : 'to'
-        const receivedAttribute = receivedColor(
-          hasAttribute
-            ? printAttribute(name, receivedValue)
-            : 'attribute was not found',
-        )
-        const expectedMsg = `Expected the element ${to} have attribute:\n  ${expectedColor(
-          printAttribute(name, expectedValue),
-        )}`
+        const receivedAttribute = hasAttribute
+          ? printAttribute(name, receivedValue)
+          : null
         const matcher = matcherHint(
           `${this.isNot ? '.not' : ''}.toHaveAttribute`,
           'element',
@@ -127,7 +120,13 @@ const extensions = {
             comment: getAttributeComment(name, expectedValue),
           },
         )
-        return `${matcher}\n\n${expectedMsg}\nReceived:\n  ${receivedAttribute}`
+        return getMessage(
+          matcher,
+          `Expected the element ${to} have attribute`,
+          printAttribute(name, expectedValue),
+          'Received',
+          receivedAttribute,
+        )
       },
     }
   },


Test patch:
diff --git a/src/__tests__/element-queries.js b/src/__tests__/element-queries.js
index 6bf03ed..39a0eec 100644
--- a/src/__tests__/element-queries.js
+++ b/src/__tests__/element-queries.js
@@ -114,6 +114,10 @@ test('using jest helpers to assert element states', () => {
   expect(() =>
     expect(queryByTestId('count-value')).not.toHaveTextContent('2'),
   ).toThrowError()
+
+  expect(() =>
+    expect({thisIsNot: 'an html element'}).toBeInTheDOM(),
+  ).toThrowError()
 })
 
 test('using jest helpers to check element attributes', () => {