diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml
index 93c0db3..81b7312 100644
--- a/.github/workflows/nodejs.yml
+++ b/.github/workflows/nodejs.yml
@@ -25,6 +25,10 @@ jobs:
npx prettier --check .
- run: npm run build
- run: npm test
+ env:
+ # Used by chalk. Ensures output from Jest includes ANSI escape
+ # characters that are needed to match test snapshots.
+ FORCE_COLOR: true
- run: npx codecov
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
diff --git a/README.md b/README.md
index c1f0b8d..db4b0e6 100644
--- a/README.md
+++ b/README.md
@@ -22,12 +22,16 @@ To activate it in your Jest environment you have to include it in your configura
}
```
-### Without Jest
+### With Playwright test runner
-```javascript
-import expect from "expect-playwright"
+To activate with the Playwright test runner, use `expect.extend` to add the `expect-playwright` matchers.
-await expect(page).toHaveText("#foo", "my text")
+```js
+// folio.config.ts
+import { expect } from "@playwright/test"
+import { matchers } from "expect-playwright"
+
+expect.extend(matchers)
```
## Why do I need it
diff --git a/src/__snapshots__/index.test.ts.snap b/src/__snapshots__/index.test.ts.snap
deleted file mode 100644
index 34dbd55..0000000
--- a/src/__snapshots__/index.test.ts.snap
+++ /dev/null
@@ -1,5 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`expectPlaywright should be able to handle negative cases return right result for page and 2 arguments 1`] = `"'zzzBarzzz' is not included in 'zzzzz'."`;
-
-exports[`expectPlaywright should be able to handle negative cases return right result for page and 4 arguments 1`] = `"Error: Timeout exceed for element '#bar'"`;
diff --git a/src/index.test.ts b/src/index.test.ts
deleted file mode 100644
index 94fe597..0000000
--- a/src/index.test.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import matchers from "./matchers"
-
-import expectPlaywright from "."
-
-describe("expect-playwright", () => {
- afterEach(async () => {
- await page.setContent("")
- })
- it("should apply the functions", () => {
- for (let matcher in matchers) {
- // @ts-ignore
- expect(expect(null)[matcher]).not.toBeUndefined()
- }
- })
- it("should be possible to use a not selector", async () => {
- await page.setContent(`
zzzBarzzz
`)
- await expect(page).not.toHaveText("This is definitely not there")
- })
- it("should be possible to use a normal selector", async () => {
- await page.setContent(`zzzBarzzz
`)
- await expect(page).toHaveText("zzzBarzzz")
- })
-})
-
-describe("expectPlaywright", () => {
- afterEach(async () => {
- await page.setContent("")
- })
- describe("should be able to handle positive cases", () => {
- it("return right result for page and 2 arguments", async () => {
- await page.setContent(`zzzBarzzz
`)
- expect(await expectPlaywright(page).toHaveText("zzzBarzzz")).toBe(true)
- })
- it("return right result for page and 3 arguments", async () => {
- await page.setContent(`zzzBarzzz
`)
- expect(await expectPlaywright(page).toHaveText("#bar", "zzzBarzzz")).toBe(
- true
- )
- })
- it("return right result for element and 2 arguments", async () => {
- await page.setContent(`zzzFoozzz
`)
- const elem = await page.$("#foo")
- expect(await expectPlaywright(elem!).toHaveText("zzzFoozzz")).toBe(true)
- })
- })
- describe("should be able to handle negative cases", () => {
- it("return right result for page and 2 arguments", async () => {
- await page.setContent(`zzzzz
`)
- await expect(
- expectPlaywright(page).toHaveText("zzzBarzzz")
- ).rejects.toThrowErrorMatchingSnapshot()
- })
- it("return right result for page and 4 arguments", async () => {
- await page.setContent(`zzzBarzzz
`)
- await expect(
- expectPlaywright(page).toHaveText("#bar", "zzzBarzzz", {
- timeout: 1 * 1000,
- })
- ).rejects.toThrowErrorMatchingSnapshot()
- })
- })
-})
diff --git a/src/index.ts b/src/index.ts
index f94109d..1cad6e9 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,4 @@
import matchers from "./matchers"
-import type { Page, ElementHandle } from "playwright-core"
-import type { PlaywrightMatchers } from "../global"
// @ts-ignore
if (typeof global.expect !== "undefined") {
@@ -8,22 +6,4 @@ if (typeof global.expect !== "undefined") {
global.expect.extend(matchers)
}
-const expectWrapper = (
- pageOrElement: Page | ElementHandle
-): PlaywrightMatchers =>
- Object.entries(matchers).reduce(
- (acc, [name, matcher]) => ({
- ...acc,
- [name]: async (...args: any[]) => {
- // @ts-ignore
- const result = await matcher(pageOrElement, ...args)
- if (!result.pass) {
- throw new Error(result.message())
- }
- return true
- },
- }),
- {} as PlaywrightMatchers
- )
-
-export = expectWrapper
+export { matchers }
diff --git a/src/matchers/tests/utils.ts b/src/matchers/tests/utils.ts
index 57d3762..13299e0 100644
--- a/src/matchers/tests/utils.ts
+++ b/src/matchers/tests/utils.ts
@@ -8,3 +8,7 @@ export const testWrapper = (result: SyncExpectationResult) => {
throw new Error(result.message())
}
}
+
+export const assertSnapshot = async (fn: () => Promise) => {
+ await expect(fn).rejects.toThrowErrorMatchingSnapshot()
+}
diff --git a/src/matchers/toEqualText/__snapshots__/index.test.ts.snap b/src/matchers/toEqualText/__snapshots__/index.test.ts.snap
index d03b6c7..d544ad6 100644
--- a/src/matchers/toEqualText/__snapshots__/index.test.ts.snap
+++ b/src/matchers/toEqualText/__snapshots__/index.test.ts.snap
@@ -1,9 +1,30 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`toEqualText selector negative 1`] = `"'not-existing' does not equal 'zzzBarzzz' of '#foobar'."`;
+exports[`toEqualText element negative 1`] = `
+"[2mexpect([22m[31mreceived[39m[2m).[22mtoEqualText[2m([22m[32mexpected[39m[2m)[22m
-exports[`toEqualText selector positive 1`] = `"'Bar' does equal 'Bar'."`;
+Expected: [32m\\"not-existing\\"[39m
+Received: [31m\\"zzzBarzzz\\"[39m"
+`;
-exports[`toEqualText selector positive frame 1`] = `"'Example Domain' does equal 'Example Domain'."`;
+exports[`toEqualText page negative 1`] = `
+"[2mexpect([22m[31mreceived[39m[2m).[22mtoEqualText[2m([22m[32mexpected[39m[2m)[22m
+
+Expected: [32m\\"not-existing\\"[39m
+Received: [31m\\"zzzBarzzz\\"[39m"
+`;
+
+exports[`toEqualText selector negative 1`] = `
+"[2mexpect([22m[31mreceived[39m[2m).[22mtoEqualText[2m([22m[32mexpected[39m[2m)[22m
+
+Expected: [32m\\"Bar\\"[39m
+Received: [31m\\"zzzBarzzz\\"[39m"
+`;
exports[`toEqualText selector timeout should throw an error after the timeout exceeds 1`] = `"Error: Timeout exceed for element '#foobar'"`;
+
+exports[`toEqualText selector with 'not' usage negative 1`] = `
+"[2mexpect([22m[31mreceived[39m[2m).[22mnot[2m.[22mtoEqualText[2m([22m[32mexpected[39m[2m)[22m
+
+Expected: not [32m\\"Bar\\"[39m"
+`;
diff --git a/src/matchers/toEqualText/index.test.ts b/src/matchers/toEqualText/index.test.ts
index edca387..835f0c0 100644
--- a/src/matchers/toEqualText/index.test.ts
+++ b/src/matchers/toEqualText/index.test.ts
@@ -1,6 +1,7 @@
-import { testWrapper } from "../tests/utils"
-
import toEqualText from "."
+import { assertSnapshot } from "../tests/utils"
+
+expect.extend({ toEqualText })
describe("toEqualText", () => {
afterEach(async () => {
@@ -10,40 +11,45 @@ describe("toEqualText", () => {
it("positive frame", async () => {
await page.setContent(``)
const iframe = await page.$("iframe")
- const result = await toEqualText(iframe!, "h1", "Example Domain")
- expect(result.pass).toBe(true)
- expect(result.message()).toMatchSnapshot()
+ await expect(iframe!).toEqualText("h1", "Example Domain")
})
it("positive", async () => {
await page.setContent(`Bar
`)
- const result = await toEqualText(page, "#foobar", "Bar")
- expect(result.pass).toBe(true)
- expect(result.message()).toMatchSnapshot()
+ await expect(page).toEqualText("#foobar", "Bar")
})
it("negative", async () => {
await page.setContent(`zzzBarzzz
`)
- expect(
- testWrapper(await toEqualText(page, "#foobar", "not-existing"))
- ).toThrowErrorMatchingSnapshot()
+ await assertSnapshot(() => expect(page).toEqualText("#foobar", "Bar"))
+ })
+ describe("with 'not' usage", () => {
+ it("positive in frame", async () => {
+ await page.setContent(``)
+ const iframe = await page.$("iframe")
+ await expect(iframe!).not.toEqualText("h1", "Foo")
+ })
+ it("positive", async () => {
+ await page.setContent(`Bar
`)
+ await expect(page).not.toEqualText("#foobar", "Foo")
+ })
+ it("negative", async () => {
+ await page.setContent(`Bar
`)
+ await assertSnapshot(() =>
+ expect(page).not.toEqualText("#foobar", "Bar")
+ )
+ })
})
describe("timeout", () => {
it("positive: should be able to use a custom timeout", async () => {
setTimeout(async () => {
await page.setContent(`Bar
`)
}, 500)
- expect(testWrapper(await toEqualText(page, "#foobar", "Bar"))).toBe(
- true
- )
+ await expect(page).toEqualText("#foobar", "Bar")
})
it("should throw an error after the timeout exceeds", async () => {
const start = new Date().getTime()
- expect(
- testWrapper(
- await toEqualText(page, "#foobar", "Bar", {
- timeout: 1 * 1000,
- })
- )
- ).toThrowErrorMatchingSnapshot()
+ await assertSnapshot(() =>
+ expect(page).toEqualText("#foobar", "Bar", { timeout: 1 * 1000 })
+ )
const duration = new Date().getTime() - start
expect(duration).toBeLessThan(1500)
})
@@ -53,28 +59,24 @@ describe("toEqualText", () => {
it("positive", async () => {
await page.setContent(`Bar
`)
const element = await page.$("#foobar")
- expect(element).not.toBe(null)
- expect(testWrapper(await toEqualText(element!, "Bar"))).toBe(true)
+ expect(element).not.toBeNull()
+ await expect(element!).toEqualText("Bar")
})
it("negative", async () => {
await page.setContent(`zzzBarzzz
`)
const element = await page.$("#foobar")
- expect(element).not.toBe(null)
- expect(
- testWrapper(await toEqualText(element!, "not-existing"))
- ).toThrowError()
+ expect(element).not.toBeNull()
+ await assertSnapshot(() => expect(element!).toEqualText("not-existing"))
})
})
describe("page", () => {
it("positive", async () => {
await page.setContent(`Bar
`)
- expect(testWrapper(await toEqualText(page, "Bar"))).toBe(true)
+ await expect(page).toEqualText("Bar")
})
it("negative", async () => {
await page.setContent(`zzzBarzzz
`)
- expect(
- testWrapper(await toEqualText(page, "not-existing"))
- ).toThrowError()
+ await assertSnapshot(() => expect(page).toEqualText("not-existing"))
})
})
})
diff --git a/src/matchers/toEqualText/index.ts b/src/matchers/toEqualText/index.ts
index 318ff79..cf355e2 100644
--- a/src/matchers/toEqualText/index.ts
+++ b/src/matchers/toEqualText/index.ts
@@ -1,30 +1,20 @@
import { SyncExpectationResult } from "expect/build/types"
-import { getElementText, quote, InputArguments } from "../utils"
+import { getElementText, getMessage, InputArguments } from "../utils"
-const toEqualText = async (
+const toEqualText: jest.CustomMatcher = async function (
...args: InputArguments
-): Promise => {
+): Promise {
try {
- const { elementHandle, selector, expectedValue } = await getElementText(
- ...args
- )
+ const { elementHandle, expectedValue } = await getElementText(...args)
/* istanbul ignore next */
- const actualTextContent = await elementHandle.evaluate(
+ const actualTextContent = await elementHandle.evaluate(
(el) => el.textContent
)
- if (actualTextContent === expectedValue) {
- return {
- pass: true,
- message: () =>
- `${quote(expectedValue)} does equal ${quote(actualTextContent)}.`,
- }
- }
+
return {
- pass: false,
+ pass: actualTextContent === expectedValue,
message: () =>
- `${quote(expectedValue)} does not equal ${quote(actualTextContent)}${
- selector ? " of " + quote(selector) + "." : "."
- }`,
+ getMessage(this, "toEqualText", expectedValue, actualTextContent),
}
} catch (err) {
return {
diff --git a/src/matchers/utils.ts b/src/matchers/utils.ts
index 9a774a3..4ea35cb 100644
--- a/src/matchers/utils.ts
+++ b/src/matchers/utils.ts
@@ -113,4 +113,22 @@ export const getElementText = async (
throw new Error(`Invalid input length: ${args.length}`)
}
-export const quote = (val: string | null) => `'${val}'`
+export const quote = (val: string | null) => (val === null ? "" : `'${val}'`)
+
+export const getMessage = (
+ { isNot, promise, utils }: jest.MatcherContext,
+ matcher: string,
+ expected: string | null,
+ received: string | null
+) => {
+ const message = isNot
+ ? `Expected: not ${utils.printExpected(expected)}`
+ : `Expected: ${utils.printExpected(expected)}\n` +
+ `Received: ${utils.printReceived(received)}`
+
+ return (
+ utils.matcherHint(matcher, undefined, undefined, { isNot, promise }) +
+ "\n\n" +
+ message
+ )
+}