diff --git a/packages/dom/package.json b/packages/dom/package.json index f50a584..407cac0 100644 --- a/packages/dom/package.json +++ b/packages/dom/package.json @@ -40,12 +40,20 @@ }, "devDependencies": { "@assertive-ts/core": "workspace:^", + "@testing-library/dom": "^10.1.0", + "@testing-library/react": "^16.0.0", "@types/jsdom-global": "^3", "@types/mocha": "^10.0.6", "@types/node": "^20.11.19", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@types/react-test-renderer": "^18", "jsdom": "^24.0.0", "jsdom-global": "^3.0.2", "mocha": "^10.3.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-test-renderer": "^18.3.1", "semantic-release": "^23.0.2", "semantic-release-yarn": "^3.0.2", "ts-node": "^10.9.2", diff --git a/packages/dom/src/lib/ElementAssertion.ts b/packages/dom/src/lib/ElementAssertion.ts new file mode 100644 index 0000000..d72b8b9 --- /dev/null +++ b/packages/dom/src/lib/ElementAssertion.ts @@ -0,0 +1,33 @@ +import { Assertion, AssertionError } from "@assertive-ts/core"; + +export class ElementAssertion extends Assertion { + + public constructor(actual: T) { + super(actual); + } + + /** + * Check if the element is in the document. + * + * @returns the assertion instance. + */ + public toBeInTheDocument(): this { + const error = new AssertionError({ + actual: this.actual, + message: "Expected the element to be in the document", + }); + const invertedError = new AssertionError({ + actual: this.actual, + message: "Expected the element to NOT be in the document", + }); + + return this.execute({ + assertWhen: ( + this.actual.ownerDocument.defaultView !== null + && this.actual.ownerDocument === this.actual.getRootNode({ composed: true }) + ), + error, + invertedError, + }); + } +} diff --git a/packages/dom/test/unit/lib/ElementAssertion.test.tsx b/packages/dom/test/unit/lib/ElementAssertion.test.tsx new file mode 100644 index 0000000..804bc53 --- /dev/null +++ b/packages/dom/test/unit/lib/ElementAssertion.test.tsx @@ -0,0 +1,45 @@ +import { AssertionError, expect } from "@assertive-ts/core"; +import { render } from "@testing-library/react"; +import { ReactElement } from "react"; + +import { ElementAssertion } from "../../../src/lib/ElementAssertion"; + +function TestComponent(): ReactElement { + return ( +
+ +
+ ); +} + +describe("[Unit] ElementAssertion.test.ts", () => { + describe(".toBeInTheDocument", () => { + context("when the element is in the document", () => { + it("returns the assertion instance", async () => { + const { findByRole } = render(); + const button = await findByRole("button", { name: "click me" }); + const test = new ElementAssertion(button); + + expect(test.toBeInTheDocument()).toBeEqual(test); + + expect(() => test.not.toBeInTheDocument()) + .toThrowError(AssertionError) + .toHaveMessage("Expected the element to NOT be in the document"); + }); + }); + + context("when the element is not in the document", () => { + it("throws an assertion error", () => { + const detachedElement = document.createElement("div"); + + const test = new ElementAssertion(detachedElement); + + expect(() => test.toBeInTheDocument()) + .toThrowError(AssertionError) + .toHaveMessage("Expected the element to be in the document"); + + expect(test.not.toBeInTheDocument()).toBeEqual(test); + }); + }); + }); +}); diff --git a/packages/dom/tsconfig.json b/packages/dom/tsconfig.json index 2d0d912..17583f4 100644 --- a/packages/dom/tsconfig.json +++ b/packages/dom/tsconfig.json @@ -2,6 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "lib": ["DOM", "DOM.Iterable"], + "jsx": "react-jsx", "outDir": "./build", "typeRoots": [ "../../node_modules/@types/", diff --git a/yarn.lock b/yarn.lock index 10a6b49..d815628 100644 --- a/yarn.lock +++ b/yarn.lock @@ -50,13 +50,21 @@ __metadata: resolution: "@assertive-ts/dom@workspace:packages/dom" dependencies: "@assertive-ts/core": "workspace:^" + "@testing-library/dom": "npm:^10.1.0" + "@testing-library/react": "npm:^16.0.0" "@types/jsdom-global": "npm:^3" "@types/mocha": "npm:^10.0.6" "@types/node": "npm:^20.11.19" + "@types/react": "npm:^18.3.3" + "@types/react-dom": "npm:^18.3.0" + "@types/react-test-renderer": "npm:^18" fast-deep-equal: "npm:^3.1.3" jsdom: "npm:^24.0.0" jsdom-global: "npm:^3.0.2" mocha: "npm:^10.3.0" + react: "npm:^18.3.1" + react-dom: "npm:^18.3.1" + react-test-renderer: "npm:^18.3.1" semantic-release: "npm:^23.0.2" semantic-release-yarn: "npm:^3.0.2" ts-node: "npm:^10.9.2" @@ -113,6 +121,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.10.4": + version: 7.24.6 + resolution: "@babel/code-frame@npm:7.24.6" + dependencies: + "@babel/highlight": "npm:^7.24.6" + picocolors: "npm:^1.0.0" + checksum: 10/e9b70af2a9c7c734ac36c2e6e1da640a6e0a483bfba7cf620226a1226a2e6d64961324b02d786e06ce72f0aa329e190dfc49128367a2368b69e2219ffddcdcc5 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.23.5": version: 7.23.5 resolution: "@babel/compat-data@npm:7.23.5" @@ -257,6 +275,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-validator-identifier@npm:7.24.6" + checksum: 10/7e725ef0684291ca3306d5174a5d1cd9072ad58ba444cfa50aaf92a5c59dd723fa15031733ac598bb6b066cb62c2472e14cd82325522348977a72e99aa21b97a + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.23.5": version: 7.23.5 resolution: "@babel/helper-validator-option@npm:7.23.5" @@ -286,6 +311,18 @@ __metadata: languageName: node linkType: hard +"@babel/highlight@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/highlight@npm:7.24.6" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.24.6" + chalk: "npm:^2.4.2" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 10/e11cd39ceb01c9b5e4f2684a45caefe7b2d7bb74997c30922e6b4063a6f16aff88356091350f0af01f044e1a198579a6b5c4161a84d0a6090e63a41167569daf + languageName: node + linkType: hard + "@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9": version: 7.23.9 resolution: "@babel/parser@npm:7.23.9" @@ -449,6 +486,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.12.5": + version: 7.24.6 + resolution: "@babel/runtime@npm:7.24.6" + dependencies: + regenerator-runtime: "npm:^0.14.0" + checksum: 10/6c4e12731cd9206a883c19d48fa04f6aaaf7ee83f049b22631e6521b866edc20832b4d5db30aa86d8ae799c4dcf57761fe8a4af2bf7e233245c079c1dafb5668 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.18.9, @babel/runtime@npm:^7.7.6": version: 7.23.9 resolution: "@babel/runtime@npm:7.23.9" @@ -1578,6 +1624,42 @@ __metadata: languageName: node linkType: hard +"@testing-library/dom@npm:^10.1.0": + version: 10.1.0 + resolution: "@testing-library/dom@npm:10.1.0" + dependencies: + "@babel/code-frame": "npm:^7.10.4" + "@babel/runtime": "npm:^7.12.5" + "@types/aria-query": "npm:^5.0.1" + aria-query: "npm:5.3.0" + chalk: "npm:^4.1.0" + dom-accessibility-api: "npm:^0.5.9" + lz-string: "npm:^1.5.0" + pretty-format: "npm:^27.0.2" + checksum: 10/6d6ef942deedf547180c76d4cc2c43fe8e52a98ef68be6ba7382a43d3b1e1e5696d9c32ae0b2df12c92ea50023187d132ad2542fc118ba4b900f149e97d019e0 + languageName: node + linkType: hard + +"@testing-library/react@npm:^16.0.0": + version: 16.0.0 + resolution: "@testing-library/react@npm:16.0.0" + dependencies: + "@babel/runtime": "npm:^7.12.5" + peerDependencies: + "@testing-library/dom": ^10.0.0 + "@types/react": ^18.0.0 + "@types/react-dom": ^18.0.0 + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10/b32894be94e31276138decfa6bcea69dfebc0c37cf91499ff6c878f41eb1154a43a7df6eb1e72e7bede78468af6cb67ca59e4acd3206b41f3ecdae2c6efdf67e + languageName: node + linkType: hard + "@tsconfig/node10@npm:^1.0.7": version: 1.0.9 resolution: "@tsconfig/node10@npm:1.0.9" @@ -1623,6 +1705,13 @@ __metadata: languageName: node linkType: hard +"@types/aria-query@npm:^5.0.1": + version: 5.0.4 + resolution: "@types/aria-query@npm:5.0.4" + checksum: 10/c0084c389dc030daeaf0115a92ce43a3f4d42fc8fef2d0e22112d87a42798d4a15aac413019d4a63f868327d52ad6740ab99609462b442fe6b9286b172d2e82e + languageName: node + linkType: hard + "@types/babel__core@npm:^7.1.14": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" @@ -1765,6 +1854,41 @@ __metadata: languageName: node linkType: hard +"@types/prop-types@npm:*": + version: 15.7.12 + resolution: "@types/prop-types@npm:15.7.12" + checksum: 10/ac16cc3d0a84431ffa5cfdf89579ad1e2269549f32ce0c769321fdd078f84db4fbe1b461ed5a1a496caf09e637c0e367d600c541435716a55b1d9713f5035dfe + languageName: node + linkType: hard + +"@types/react-dom@npm:^18.3.0": + version: 18.3.0 + resolution: "@types/react-dom@npm:18.3.0" + dependencies: + "@types/react": "npm:*" + checksum: 10/6ff53f5a7b7fba952a68e114d3b542ebdc1e87a794234785ebab0bcd9bde7fb4885f21ebaf93d26dc0a1b5b93287f42cad68b78ae04dddf6b20da7aceff0beaf + languageName: node + linkType: hard + +"@types/react-test-renderer@npm:^18": + version: 18.3.0 + resolution: "@types/react-test-renderer@npm:18.3.0" + dependencies: + "@types/react": "npm:*" + checksum: 10/c53683990bd194cb68e3987bda79c78eff41517f7a747e92f3e54217c2ce3addd031b8a45bf631982c909cc2caeeb905372f322758e05bb76c03754a3f24426e + languageName: node + linkType: hard + +"@types/react@npm:*, @types/react@npm:^18.3.3": + version: 18.3.3 + resolution: "@types/react@npm:18.3.3" + dependencies: + "@types/prop-types": "npm:*" + csstype: "npm:^3.0.2" + checksum: 10/68e203b7f1f91d6cf21f33fc7af9d6d228035a26c83f514981e54aa3da695d0ec6af10c277c6336de1dd76c4adbe9563f3a21f80c4462000f41e5f370b46e96c + languageName: node + linkType: hard + "@types/semver@npm:^7.3.12, @types/semver@npm:^7.5.0": version: 7.5.7 resolution: "@types/semver@npm:7.5.7" @@ -2284,6 +2408,15 @@ __metadata: languageName: node linkType: hard +"aria-query@npm:5.3.0": + version: 5.3.0 + resolution: "aria-query@npm:5.3.0" + dependencies: + dequal: "npm:^2.0.3" + checksum: 10/c3e1ed127cc6886fea4732e97dd6d3c3938e64180803acfb9df8955517c4943760746ffaf4020ce8f7ffaa7556a3b5f85c3769a1f5ca74a1288e02d042f9ae4e + languageName: node + linkType: hard + "array-buffer-byte-length@npm:^1.0.1": version: 1.0.1 resolution: "array-buffer-byte-length@npm:1.0.1" @@ -3186,6 +3319,13 @@ __metadata: languageName: node linkType: hard +"csstype@npm:^3.0.2": + version: 3.1.3 + resolution: "csstype@npm:3.1.3" + checksum: 10/f593cce41ff5ade23f44e77521e3a1bcc2c64107041e1bf6c3c32adc5187d0d60983292fda326154d20b01079e24931aa5b08e4467cc488b60bb1e7f6d478ade + languageName: node + linkType: hard + "data-urls@npm:^5.0.0": version: 5.0.0 resolution: "data-urls@npm:5.0.0" @@ -3316,6 +3456,13 @@ __metadata: languageName: node linkType: hard +"dequal@npm:^2.0.3": + version: 2.0.3 + resolution: "dequal@npm:2.0.3" + checksum: 10/6ff05a7561f33603df87c45e389c9ac0a95e3c056be3da1a0c4702149e3a7f6fe5ffbb294478687ba51a9e95f3a60e8b6b9005993acd79c292c7d15f71964b6b + languageName: node + linkType: hard + "detect-newline@npm:^3.0.0": version: 3.1.0 resolution: "detect-newline@npm:3.1.0" @@ -3385,6 +3532,13 @@ __metadata: languageName: node linkType: hard +"dom-accessibility-api@npm:^0.5.9": + version: 0.5.16 + resolution: "dom-accessibility-api@npm:0.5.16" + checksum: 10/377b4a7f9eae0a5d72e1068c369c99e0e4ca17fdfd5219f3abd32a73a590749a267475a59d7b03a891f9b673c27429133a818c44b2e47e32fec024b34274e2ca + languageName: node + linkType: hard + "dot-prop@npm:^5.1.0": version: 5.3.0 resolution: "dot-prop@npm:5.3.0" @@ -5736,7 +5890,7 @@ __metadata: languageName: node linkType: hard -"js-tokens@npm:^4.0.0": +"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" checksum: 10/af37d0d913fb56aec6dc0074c163cc71cd23c0b8aad5c2350747b6721d37ba118af35abdd8b33c47ec2800de07dedb16a527ca9c530ee004093e04958bd0cbf2 @@ -6269,6 +6423,17 @@ __metadata: languageName: node linkType: hard +"loose-envify@npm:^1.1.0": + version: 1.4.0 + resolution: "loose-envify@npm:1.4.0" + dependencies: + js-tokens: "npm:^3.0.0 || ^4.0.0" + bin: + loose-envify: cli.js + checksum: 10/6517e24e0cad87ec9888f500c5b5947032cdfe6ef65e1c1936a0c48a524b81e65542c9c3edc91c97d5bddc806ee2a985dbc79be89215d613b1de5db6d1cfe6f4 + languageName: node + linkType: hard + "lru-cache@npm:^10.0.1, lru-cache@npm:^9.1.1 || ^10.0.0": version: 10.2.0 resolution: "lru-cache@npm:10.2.0" @@ -6301,6 +6466,15 @@ __metadata: languageName: node linkType: hard +"lz-string@npm:^1.5.0": + version: 1.5.0 + resolution: "lz-string@npm:1.5.0" + bin: + lz-string: bin/bin.js + checksum: 10/e86f0280e99a8d8cd4eef24d8601ddae15ce54e43ac9990dfcb79e1e081c255ad24424a30d78d2ad8e51a8ce82a66a930047fed4b4aa38c6f0b392ff9300edfc + languageName: node + linkType: hard + "make-dir@npm:^4.0.0": version: 4.0.0 resolution: "make-dir@npm:4.0.0" @@ -7018,7 +7192,7 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4.0.1": +"object-assign@npm:^4.0.1, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" checksum: 10/fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f @@ -7536,6 +7710,17 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:^27.0.2": + version: 27.5.1 + resolution: "pretty-format@npm:27.5.1" + dependencies: + ansi-regex: "npm:^5.0.1" + ansi-styles: "npm:^5.0.0" + react-is: "npm:^17.0.1" + checksum: 10/248990cbef9e96fb36a3e1ae6b903c551ca4ddd733f8d0912b9cc5141d3d0b3f9f8dfb4d799fb1c6723382c9c2083ffbfa4ad43ff9a0e7535d32d41fd5f01da6 + languageName: node + linkType: hard + "pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": version: 29.7.0 resolution: "pretty-format@npm:29.7.0" @@ -7685,6 +7870,32 @@ __metadata: languageName: node linkType: hard +"react-dom@npm:^18.3.1": + version: 18.3.1 + resolution: "react-dom@npm:18.3.1" + dependencies: + loose-envify: "npm:^1.1.0" + scheduler: "npm:^0.23.2" + peerDependencies: + react: ^18.3.1 + checksum: 10/3f4b73a3aa083091173b29812b10394dd06f4ac06aff410b74702cfb3aa29d7b0ced208aab92d5272919b612e5cda21aeb1d54191848cf6e46e9e354f3541f81 + languageName: node + linkType: hard + +"react-is@npm:^16.12.0 || ^17.0.0 || ^18.0.0, react-is@npm:^18.3.1": + version: 18.3.1 + resolution: "react-is@npm:18.3.1" + checksum: 10/d5f60c87d285af24b1e1e7eaeb123ec256c3c8bdea7061ab3932e3e14685708221bf234ec50b21e10dd07f008f1b966a2730a0ce4ff67905b3872ff2042aec22 + languageName: node + linkType: hard + +"react-is@npm:^17.0.1": + version: 17.0.2 + resolution: "react-is@npm:17.0.2" + checksum: 10/73b36281e58eeb27c9cc6031301b6ae19ecdc9f18ae2d518bdb39b0ac564e65c5779405d623f1df9abf378a13858b79442480244bd579968afc1faf9a2ce5e05 + languageName: node + linkType: hard + "react-is@npm:^18.0.0": version: 18.2.0 resolution: "react-is@npm:18.2.0" @@ -7692,6 +7903,40 @@ __metadata: languageName: node linkType: hard +"react-shallow-renderer@npm:^16.15.0": + version: 16.15.0 + resolution: "react-shallow-renderer@npm:16.15.0" + dependencies: + object-assign: "npm:^4.1.1" + react-is: "npm:^16.12.0 || ^17.0.0 || ^18.0.0" + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + checksum: 10/06457fe5bcaa44aeca998905b6849304742ea1cc2d3841e4a0964c745ff392bc4dec07f8c779f317faacce3a0bf6f84e15020ac0fa81adb931067dbb0baf707b + languageName: node + linkType: hard + +"react-test-renderer@npm:^18.3.1": + version: 18.3.1 + resolution: "react-test-renderer@npm:18.3.1" + dependencies: + react-is: "npm:^18.3.1" + react-shallow-renderer: "npm:^16.15.0" + scheduler: "npm:^0.23.2" + peerDependencies: + react: ^18.3.1 + checksum: 10/d53137315c677bdfba702a7179a69828233fc7635ae1e0c03b203923d643400ace72b343cb3dd3dafba8911c20bef53f55bff7aa2e4ddff3ccc423fdd9deeee2 + languageName: node + linkType: hard + +"react@npm:^18.3.1": + version: 18.3.1 + resolution: "react@npm:18.3.1" + dependencies: + loose-envify: "npm:^1.1.0" + checksum: 10/261137d3f3993eaa2368a83110466fc0e558bc2c7f7ae7ca52d94f03aac945f45146bd85e5f481044db1758a1dbb57879e2fcdd33924e2dde1bdc550ce73f7bf + languageName: node + linkType: hard + "read-cmd-shim@npm:^4.0.0": version: 4.0.0 resolution: "read-cmd-shim@npm:4.0.0" @@ -8029,6 +8274,15 @@ __metadata: languageName: node linkType: hard +"scheduler@npm:^0.23.2": + version: 0.23.2 + resolution: "scheduler@npm:0.23.2" + dependencies: + loose-envify: "npm:^1.1.0" + checksum: 10/e8d68b89d18d5b028223edf090092846868a765a591944760942b77ea1f69b17235f7e956696efbb62c8130ab90af7e0949bfb8eba7896335507317236966bc9 + languageName: node + linkType: hard + "semantic-release-yarn@npm:^3.0.2": version: 3.0.2 resolution: "semantic-release-yarn@npm:3.0.2"