playwright
playwright copied to clipboard
[Feature] add option to normalize whitespace to expect().toHaveValue()
System info
- Playwright Version: [v1.30]
- Operating System: [Windows 10]
- Browser: [Chromium]
- Other info:
Source code
const unformattedPrice = "11250";
await purchaseVehiclePage.enterAskingPrice(unformattedPrice);
await purchaseVehiclePage.enterTradeInPrice(unformattedPrice);
await purchaseVehiclePage.enterResalePrice(unformattedPrice);
await purchaseVehiclePage.removeFieldFocus();
const priceFields = [
purchaseVehiclePage.askingPriceField,
purchaseVehiclePage.tradeInPriceField,
purchaseVehiclePage.resalePriceField
];
let expectedFormattedPrice = Utils.removeCurrency(Utils.convertToCurrencyFormat(parseInt(unformattedPrice),
workerInfo.project.name));
for (const priceField of priceFields) {
if(workerInfo.project.name==='at') {
await expect(await priceField.inputValue()).toContain("11 250,00");
} else {
await purchaseVehicleAssertion.assertPriceFormat(priceField, expectedFormattedPrice);
}
}
Steps:
Hello, the code itself will probably not have explained much, so here's how to reproduce: Have a value > 1000. Have an input field that instead of a "." or a "," puts a whitespace to separate "numeric" values (which are actually string), so for example "11250" would become "11 250,00" or 1000235 would become 1 000 235,00 Grab the .inputValue() of the field after typing or filling an unformatted raw numeric value into the field.
Assert the field with expect(await element.inputValue()).toBe("11 250,00")
Expected
Since "11 250,00" which was fetched from inputValue() is the same as "11 250,00" which was set there as a string in assertions, using any of the matching assertions should correctly deduce the two fields as equal.
Actual If the inptValue() contains a whitespace, using assertions like .toBe() or .toContain(), comparing string with identical string causes an assertion error. This issue is not reproduced if the inputValue() of the string does not contain a whitespace, so if the number is parsed to "11.250,00" any assertion asserting this inputValue() to be or contain "11.250,00" will pass.
Error: expect(received).toBe(expected) // Object.is equality
Expected: "11 250,00" Received: "11 250,00"
141 | for (const priceField of priceFields) { 142 | if(workerInfo.project.name==='at') {
143 | await expect(await priceField.inputValue()).toBe("11 250,00"); | ^ 144 | } else { 145 | await purchaseVehicleAssertion.assertPriceFormat(priceField, expectedFormattedPrice); 146 | }
After some debugging it looks like .inputValue() returns a different whitespace charCode.
If a whitespace is obtained using .inputValue() it's charCode will be 160 (or a Non-Breaking Space)
Unicode representation: U+00A0
HTML entity:
while a charCode in a regular string within a program is usually charCode 32.
Unicode representation: U+0020
HTML entity:  
or simply a regular space character
This causes inconsistencies if ever an input from the web is fetched with .inputValue() to be used in further comparison operations, be it JavaScripts default equal operators or any sort of assertions.
Proposed solution to the bug: Make the whitespace that is returned from .inputValue() action be a regular space character or charCode 32 instead of a nbsp with charCode 160 so the value that is obtained in this way can be compared.
@kLjubomir I tried to reproduce this, but was not able to, unfortunately. Could you please share the repro that we can run locally, including the page you are testing?
I tried various <input>
fields with emulating locale
to "fr-Fr"
and/or changing my computer's locale, but was not able to reproduce the issue. I suspect this may be specific to your particular web page.
So the locale on the page yields: console.log(navigator.languages); ['en-US', 'en']
I don't think that the nested HTML will tell you much, but I can say that the page is coded in Angular, will still attach the element as an example below.
I have tried using .inputValue() on google's textarea element and confirmed that the whitespace returned is a regular whitespace, so I'm really not sure why on the page I'm working on it was returned as a nbsp, maybe it really could be due to the way that the page is coded, so I am not sure what to do with this information, I used normalization in these cases where it was required, but is it possible for me to locally overwrite playwrights inputValue function, so I could code in my regex to regulate the whitespace charCode?
for keeping the business secret reasons I can not provide more information like page's domain and credentials etc.
<div _ngcontent-yex-c327="" ngclass.lt-mv="mobile" class="content-box"><vpfa-number-field _ngcontent-yex-c752="" fcname="askingPrice" fieldwidth="100%" _nghost-yex-c281=""><vpfa-field-container _ngcontent-yex-c281="" _nghost-yex-c274=""><vpfa-field-validation-container _ngcontent-yex-c274="" _nghost-yex-c273=""><div _ngcontent-yex-c273="" class="field-validation-container"><div _ngcontent-yex-c273="" vpfagetclientboundingrect="" class="currency"><nz-form-control _ngcontent-yex-c274="" class="ng-tns-c253-963 ant-form-item-control ant-col ng-star-inserted"><div class="ant-form-item-control-input ng-tns-c253-963"><div class="ant-form-item-control-input-content ng-tns-c253-963" style="flex-direction: row; box-sizing: border-box; display: flex;"><nz-input-group _ngcontent-yex-c281="" class="ng-tns-c253-963 ant-input-affix-wrapper ant-input-affix-wrapper-sm" style="flex: 1 1 100%; box-sizing: border-box; max-width: 100%;"><span nz-input-group-slot="" type="prefix" class="ant-input-prefix ng-star-inserted"><!----><vpfa-active-currency _ngcontent-yex-c281="" _nghost-yex-c280="" class="ng-star-inserted"><span _ngcontent-yex-c280="" class="input-hint-mode ng-star-inserted"> € <!----><!----><!----></span><!----></vpfa-active-currency><!----><!----><!----></span><!----><input _ngcontent-yex-c281="" nz-input="" type="text" vpfacharcountlimiter="" vpfanumberformatter="" class="ant-input ng-untouched ng-dirty ng-valid ant-input-sm ng-star-inserted currency-symbol" placeholder=""><!----><!----><!----><!----><!----><!----><!----><!----></nz-input-group></div><span class="ant-form-item-children-icon ng-tns-c253-963"><!----></span></div><!----><!----></nz-form-control></div><div _ngcontent-yex-c273="" nz-popover="" nzpopovertrigger="focus" class="error-sign" hidden="" style="top: 3px; right: -25px;"><!----></div><!----></div></vpfa-field-validation-container></vpfa-field-container><!----><!----></vpfa-number-field><!----></div>
@kLjubomir I agree this is most likely page-specific.
is it possible for me to locally overwrite playwrights inputValue function
That's not possible. I'd recommend creating a helper function that you call instead of inputValue()
:
export function getInputValue(locator) {
const value = await locator.inputValue();
return value.replace(...);
}
That said, we can probably add an option to expect(locator).toHaveValue()
, something like normalizeWhiteSpace
or similar. Let's use this issue to track this feature request.
Playwright Version: [v1.35.1] Operating System: [Windows 11] Browser: [Chromium]
In case one of them has an extra whitespace, when two distinct texts are asserted by the method "toHaveText", it does not throw an error and the test passes.
The text of the web element ="Book Store Application" await expect(page.getByText("Book Store Application")).toHaveText("Book Store Application"); //it is supported to pass and it passes await expect(page.getByText("Book Store Application")).toHaveText(" Book Store Application"); //but it is not expexted to pass but it passes as well :)