A central home for tutorials, tooling, and showcases of the Playwright ecosystem.
This is the source of playwright.tech. A Next.js based application hosted on Vercel.
Expect utility matcher functions to simplify expect statements for the usage with Playwright Test or Jest Playwright.
Home Page: https://playwright-community.github.io/expect-playwright/
License: MIT License
A central home for tutorials, tooling, and showcases of the Playwright ecosystem.
This is the source of playwright.tech. A Next.js based application hosted on Vercel.
Currently, we are targeting various domains for our iframe tests. Ideally we would have our own test site that we can use. Perhaps just a collection of HTML files that are served with the serve
package?
Context:
Code Snippet
await expect(myModal).toHaveText("Message in modal", {
waitFor: "visible",
});
Describe the bug
I'm getting an error Error: Invalid input length: 3
.
expect-playwright/src/matchers/utils.ts
Line 39 in 463a55d
console.logs
in lib/matchers/utils.js
:
exports.getElementText = async (...args) => {
/**
* Handle the following cases:
* - expect(page).foo("bar")
* - expect(element).foo("bar")
*/
console.log(args)
console.log(args.length)
if (args.length === 2) {
With output below:
# .... very long object/elementHandle
[Symbol(kCapture)]: false
}
},
'You have entered incorrect one time pin.',
{ waitFor: 'visible' }
]
at Object.exports.getElementText (node_modules/.pnpm/registry.npmjs.org/expect-playwright/0.2.2/node_modules/expect-pla
ywright/lib/matchers/utils.js:23:15)
console.log
3
expect-playwright/src/matchers/utils.ts
Line 57 in 463a55d
* - expect(elementHandle).foo("bar", {obj})
has not yet been handled.Hey team,
May I ask how could we setup default timeout? as document said it's 30 seconds, but I don't find where we set it. Is it possible to set it from jest config also?
Thanks
Looks like toMatchText
isn't exported in index.ts
TypeError: expect(...).toMatchText is not a function
https://github.com/playwright-community/expect-playwright/releases Version 0.2.6 says:
You need to install playwight-core as a peer dependency now.
I can run expect-playwright fine without playwright-core. What am I missing?
The option waitFor
has changed to state
as part of the Playwright 1.0 release, so this needs to change as well.
interface PageWaitForSelectorOptions {
/**
* Wait for element to become visible (`visible`), hidden (`hidden`), present in dom (`attached`) or not present in dom (`detached`). Defaults to `attached`.
*/
waitFor?: "attached" | "detached" | "visible" | "hidden";
```
playwright-core
: ^1.7.1
playwright-expect
: 0.3.0
I am trying following code per documentation
await expect(page).not.toHaveSelector("#foobar", {
timeout: 1 * 1000
})
However I get following error:
TypeError: Cannot read property 'toHaveSelector' of undefined
11 |
12 | export const isWidgetMessageHidden = (page) => {
> 13 | return expect(page)
| ^
14 | .not
15 | .toHaveSelector(selectId(REFERRAL.WIDGET_MESSAGE))
16 | }
Logging shows below:
console.log(expect(page));
/* returns below, missing not method
{
toHaveText: [AsyncFunction: toHaveText],
toEqualText: [AsyncFunction: toEqualText],
toHaveSelector: [AsyncFunction: toHaveSelector],
toEqualValue: [AsyncFunction: toEqualValue]
}
*/
Am I missing something? Many thanks for these great helpers!
I just wanted to point out the Readme has not been updated with the toHaveSelectorCount documentation. I'd do it myself but I don't want to presume I 100% know how it works (although I assume it's roughly the same as toHaveSelector but with an additional param for the expected count).
Nice to see expect-playwright 😃 Considering starting using it, but I could not find info about this and was curious about a few things.
Playwright supports text selector engines like so:
const text = await page.waitFor('text=Unauthorized');
expect(await text.evaluate((el) => el.innerText)).toBe('Unauthorized');
That I would have wished to replace with:
await expect(page).toHaveText('Unauthorized'); // using the underlying text selector
The first thing I noticed is that the example at https://github.com/mxschmitt/expect-playwright#why-do-i-need-it does not show the above (nicer) way to get a text element that Playwright already supports.
I also wrote another issue that text selectors should be case insensitive and "partial match" by default, which landed in another MR, see new description here https://github.com/microsoft/playwright/blob/master/docs/selectors.md#text
The second thing I know is that an issue I wrote microsoft/playwright#1375 just landed its first merge request microsoft/playwright#1619. The text selector now pierces open shadow roots.
NOTE Text engine searches for elements inside open shadow roots, but not inside closed shadow roots or iframes.
Should/are all these features taking into consideration with these new expect functions?
The first case below does not work, whilst the second does. What is the implication of using expect(page).not.toHaveSelector
? I would have thought it would be similar to the second example, but it is not.
// Does not work
await page.click('text=Delete');
await expect(page).not.toHaveSelector(selector);
// Works
await page.click('text=Delete');
await expect(page).toHaveSelector(selector, { state: 'detached' });
Hello folks and thank you for the great work you're doing with the tool! That's amazing 😊
I'm opening this issue to request for a .toHaveFocus()
function that will allow to verify what is the actually focused element. This may become very helpful when testing for accessibility.
Actually, to determine if an element has focused on it, I have two options that are quite verbose:
const axTreeSnapshot = await page.accessibility.snapshot({ root });
// does not look very consistent on firefox from my experimentation, but I may be wrong
axTreeSnapshot.focused
or as described in microsoft/playwright#2159 (comment) with the following:
const foo1Isfocused = await page.$eval("#foo1", (el) => el === document.activeElement)
What do you think?
Hi there,
I am trying to use toEqualValue
, and noticed that it does not wait for the condition to be true as I would have expected.
Below is an example where it checks the value of an input. Since the value is not Playwright
, the test fails instantly. I would have expected it to keep checking the input value before timing out, as sometimes inputs can be filled in with a delay. The error message is 'Playwright' does not equal ''.
const qawolf = require("qawolf");
const selectors = require("./selectors/myTest.json");
let browser;
let page;
beforeAll(async () => {
browser = await qawolf.launch();
const context = await browser.newContext();
await qawolf.register(context);
page = await context.newPage();
});
afterAll(async () => {
await qawolf.stopVideos();
await browser.close();
});
test("myTest", async () => {
await page.goto("http://todomvc.com/examples/react");
await page.click(selectors["0_what_needs_to_b_input"]);
await page.type(selectors["1_what_needs_to_b_input"], "enter todo");
await page.press(selectors["2_what_needs_to_b_input"], "Enter");
const element = await page.$(selectors["2_what_needs_to_b_input"]);
await expect(element).toEqualValue("Playwright");
});
Another note - the README still says 1 second. Just wanted to see if that was still the actual timeout, or if it is just out of date.
Thanks in advance :)
Given frame = await handle.contentFrame()
.
When I need both expect(handle).toEqualText()
and expect(frame.isEnabled()).toBeTruthy()
Then it is not clear that the handle
and frame
are refering to the "same" iframe:
await expect(handle).toEqualText('#completeButton', 'Submit')
expect(await frame.isEnabled('#completeButton')).toBeTruthy()
With support Frame argument, it should be much clear:
await expect(frame).toEqualText('#completeButton', 'Submit')
expect(await frame.isEnabled('#completeButton')).toBeTruthy()
Currently I have to install both playwright and playwright-core in my package.json in order to run expect-playwright.
If I compare the subdependencies of playwright and playwright-core, they are identical. How come playwright could not be listed as the peer dependency instead?
Was thinking that it might be nice to have a shorthand
expect(page).toHaveUrl(expectedUrl);
that would be equivalent to the longer
expect(await page.url()).toEqual(expectedUrl);
Update toMatchValue
to use elementHandle.inputValue
. This is not something we should do immediately due to Playwright 1.13 just being released, but wanted to put a pin in this for the future.
Latest version (0.2.5) depends on playwright-core ^1.2.1:
expect-playwright/package.json
Line 15 in 973c949
Hi,
I tried to follow the jest-playwritght
basic example, so the following test:
test("TEST", async () => {
await page.goto("https://playwright.dev/");
const title = page.locator(".navbar__inner .navbar__title");
await expect(title).toHaveText("Playwright");
})
However, I got Error: Timeout exceed for element 'body'
. I followed the error message to here, commented out the try-catch (leaving the body of course) and I got TypeError: elementHandle.waitForSelector is not a function
- which I don't know how to solve.
At the line in question, I listed the following variables for context:
args
: [ [email protected]__inner .navbar__title ]
elementHandle
: [email protected]__inner .navbar__title
elementHandle.waitForSelector
: undefined
console.trace()
:
Trace:
at Object.getElementHandle (/home/user/project/node_modules/expect-playwright/lib/matchers/utils.js:32:21)
at runNextTicks (internal/process/task_queues.js:60:5)
at processImmediate (internal/timers.js:437:9)
at Object.toHaveText (/home/user/project/node_modules/expect-playwright/lib/matchers/toHaveText/index.js:10:50)
Hi there,
Thanks for this library! I am working to integrate it with qawolf, and I noticed that it times out very quickly when looking for text that is not on the page. This is true even if I pass a longer timeout in options
.
As a point of feedback, I was also surprised that the default timeout was only 1 second. I would have expected something longer like 30 seconds, consistent with the Playwright API.
Here is a reproduction with qawolf. Even though the text is not on the page and I wanted to wait for 30 seconds before failing, the test seems to fail instantly (Error message: Error: Timeout exceed for element 'not there'
).
Please let me know if I'm doing something wrong or missing something. Also happy to help fix this issue :)
const qawolf = require("qawolf");
let browser;
let page;
beforeAll(async () => {
browser = await qawolf.launch({ headless: false });
const context = await browser.newContext();
await qawolf.register(context);
page = await context.newPage();
});
afterAll(async () => {
await browser.close();
});
test("test", async () => {
await page.goto("http://todomvc.com/examples/react");
await page.type("input.new-todo", "create test!");
await page.press("input.new-todo", "Enter");
await page.click("input.toggle");
await page.click("button.clear-completed");
await expect(page).toHaveText("not there", { timeout: 30000 });
});
I need new assertion checking the count of elements which the selector matches.
It's very useful to verify the count of elements.
// before
await page.waitForSelector(selector);
const count = await page.$$eval(selector, (el) => el.length);
expect(count).toBe(1);
// after
await expect(page).toHaveCount(selector, 1)
It might be better to consider if the new assertion can verify the greater or less count.
await expect(page).toHaveCount(selector, '> 1')
await expect(page).toHaveGreaterThanCount(selector, 1)
I recently saw this notice on the jest-playwright
GitHub page:
⚠️ We recommend the official Playwright test-runner⚠️ It's more flexible, lightweight, optimized for Playwright, and has TypeScript support out of the box. This doesn't mean, that we stop with maintaining this package.
I decided to take the plunge, and in the process realized almost everything I had been using expect-playwright
(with jest-playwright
) for was handled by @playwright/test
.
I also ran across this comment on an issue:
With @playwright/test taking over, this repo will not likely live long, so this can be closed.
I wonder if it's time to give a heads up at the top of the README à la jest-playwright
? Could be a little softer if this repo isn't quite as close to maintenance mode, but might still be useful for new folks, or those (like me) making the move from jest-playwright
to @playwright/test
.
This fails
await expect(page).toHaveSelector('div.ember-cli-notifications-notification__container');
where this passes
await expect(page).toHaveSelector('div#content-wrapper');
are selector's something other then CSS selectors? Or perhaps I expect different behavior?
I am certain a div.ember-cli-notifications-notification__container exists on my page
<div class="ember-cli-notifications-notification__container ember-cli-notifications-notification__container--bottom-right" style="z-index: 1060;" data-test-notification-container="bottom-right">
<!----></div>
<div id="content-wrapper" class="min-100h d-flex flex-column flex-nowrap"></div>
The result messages from the matchers in expect-playwright get the job done by displaying information about what went wrong. However, Jest has some utils that are available that can make matcher messages more visually friendly as well as consistent with the default matchers built into Jest (e.g. toBe
).
I've got a WIP branch to show how this could look: https://github.com/mskelton/expect-playwright/tree/improve-matcher-hints
Hi here,
Currently, all assertions are designed to check a single element. It would be helpful to check multiple elements (list items, table cells) and assert that they contain certain text.
Just spitballing here, but this is what I'm envisioning 🤔 :
expect(page).toAllHaveText(selector, text, options)
(this would use Playwright's page.$$
method to select all elements matching the provided selector).Would love thoughts from the community. Happy to collaborate and contribute! 😄
Unrelated to this PR. I'm thinking if we should either use resetContext every where or easier migrate to the Playwright Test runner and keep an integration test for the Jest preset.
Originally posted by @mxschmitt in #102 (comment)
While trying out jest-playwright i've experienced issue with expect-playwright. My project GitHub repo. I cannot use any assertions from expect-playwright, when running tests from terminal the following error occurs:
TypeError: expect(...).toHaveTitle is not a function
1 | export async function testGoogle(){
2 | await page.screenshot({path: './target/sampleTest/sampleTest.png'})
> 3 | await expect(page).toHaveTitle('Google');
| ^
4 | }
at Object.testGoogle (src/util/sampleTest.js:3:24)
at Object.<anonymous> (src/spec/sample.spec.js:8:5)
While working on the PR for the improved matcher messages, I've noticed that there isn't any code formatting tool setup in this repository. Would you be opposed to introducing a tool such as Prettier to help with code consistency, readability, and ease of development?
What is the reason that await expect(page).toHaveText("Playwright")
has a timeout of only a 1 sec? it's a real cumbersome to pass the timeout as a second parameter every time
According to the docs helper methods liketoHaveSelector
, toHaveText
, toEqualText
, and toEqualValue
have a default timeout of 1 second.
It has a default timeout of 1 second, which you can overwrite via the options.
This is working as expected for positive assertions:
// Immediate (working)
await expect(page).toHaveSelector('#foo');
But negative assertions are defaulting to a 30 second timeout:
// 30 second timeout (not working)
await expect(page).not.toHaveSelector('#foo');
I can fix this by manually setting the timeout in options
, but it would be nice to not have to do this:
// Immediate (manual fix)
await expect(page).not.toHaveSelector('#foo', { timeout: 1 });
Configuration:
Thanks!
We should support passing a promise as an argument like so:
await expect(page.$('input')).toBeChecked()
I test multi-megabyte apps and it's huge pain having it dumped into console, sometimes multiple times. I need to scroll tons just to find which test failed.
We should have option to disable that.
I had an idea about matchers like toMatchText
/toEqualText
or future matchers like toMatchTitle
/toEqualTitle
. What if instead of having multiple matchers, we have a single matcher that if given a string, matches exactly and given a regex matches partial.
expect(page).toMatchText('.my-element', 'Playwright') // exact text match
expect(page).toMatchText('.my-element', /^Playwright$/) // full regex match
expect(page).toMatchText('.my-element', /Play/) // partial regex match
This would make it so we only have a single matcher for each purpose which could make things less confusing. That said, this might just make things more confusing.
It appears there's no type defined on PlaywrightMatchers
for toHaveSelectorCount
Although this seems to be a common problem when extending expect in jest, the editor can't find the type definition. (the test itself works since setupFilesAfterEnv
is specified)
Explicitly import "expect-playwright"
in the file works well, but do you know the other way?
To reproduce:
git clone -b repro-expect-playwright https://github.com/banyan/issue-repro.git
cd issue-repro
yarn
code .qawolf/myTest.test.ts # using vscode
.value
of an input elementv0.6.0 works fine.
Updating to 0.7.1 fails tests.
Trying to
const firstWidgetOfUser = await page.waitForSelector(DashboardSelectors.widget);
// works
expect(await firstWidgetOfUser.getAttribute('data-id')).toStrictEqual('File/my_open_cases');
// fails in 0.7.0/0.7.1, works fine in 0.6.0
await expect(firstWidgetOfUser).toHaveSelector(DashboardSelectors.chartWidget);
fails on second expect
with
TypeError: Cannot read property 'waitForSelector' of null
;
Most of the things are only type changes...
Given the following HTML:
<p></p>
The following toEqualText()
call will timeout:
await expect(page).toEqualText('p', '');
The workaround is easy enough:
expect(await page.innerText('p')).toBe('');
But it feels out of place when testing multiple elements using toEqualText()
:
await expect(page).toEqualText('.foo', 'foo');
await expect(page).toEqualText('.bar', 'bar');
await expect(page).toEqualText('.baz', 'baz');
expect(await page.innerText('.empty')).toBe('');
Ideally, toEqualText()
would support an empty string as a valid text match.
We have a lot of iframes inside our application and would like to test inside the iframe pages. It would be great if expect
could also work with a Frame object.
Hi guys,
I replaced the deprecated method toHaveText with the new one toMatchText and many of the tests failed. The reason for the failure is the presence of whitespace.
For example, this code is going to fail:
<button>
<i class="click-icon"></i>
<span>Click here</span>
</button>
------------------------
await expect(page).toMatchText('button', 'Click here');
Is there an option to modify toMatchText to run trim on textContent?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.