I have a page that shows the alert notification, and a count of alerts. The alerts come from a service on the page. I want to be able to test the different behavior with different values.
The alert icon is disabled and does not show the badge value (number of alerts) when the value is 0.
However, if the value is greater than 0, the icon is enabled, and the badge number shows up.
Simply in my code, I have a standard button, using the [disabled] and [matBadgeHidden] properties against a count value from the component.
<button mat-icon-button [disabled]="AlertCount === 0" data-testid="notification-button">
<mat-icon matBadge="{{ AlertCount }}" [matBadgeHidden]="AlertCount === 0" data-testid="notification-button-icon">notifications</mat-icon>
<!-- Include text description of the icon's meaning for screen-readers -->
<span class="cdk-visually-hidden" data-testid="notification-screen-reader-text">
You have {{ AlertCount }} alerts.
</span>
</button>
I can test either case using Cypress and the data-testid.
it('should have the alert button visible and disabled', () => {
const AlertNotificationButton = () => cy.get('[data-testid=notification-button]');
AlertNotificationButton().should('be.visible');
AlertNotificationButton().should('be.disabled');
});
it('should have 0 alerts for the notification screen reader text', () => {
const SlertScreenReaderText = () => cy.get('[data-testid=notification-screen-reader-text]');
AlertScreenReaderText().should('not.be.disabled');
AlertScreenReaderText().contains('You have 0 alerts');
});
This works in isolation, but I cannot do this via E2E tests, as I cannot control the value coming from the service (at least how I know to do it). Is there anyway to change the value using Cypress, so that my AlertCount in the code is changed to 0 or a 3 for the different test scenarios?
I expect I might be missing something bigger for this style of testing to somehow mock out services and the values returned?
EDIT
I am expecting that one option would be to simply continue to click through the application with Cypress, to go view the built up alerts, and view/delete them, so the count on the server goes to 0, which is how a user would do it?
I want to test like that completely, but was hoping I could validate some of the functionality along the way, for the visual options, and then additional testing for the complete user flow.
** EDIT 2**
I did find Cypress Intercepts, but I do not think this will work as the UI code being tested here, gets data from services in Angular, not calls directly on the URLs that Cypress can fake data from. The data might come from HTTP, or a database, etc.
Related
I have an Ionic React app that uses react-router 5 to display various pages.
The app defaults to a login form, but if users go to the support page, there is a contact form.
I'm trying to test the contact form in Playwright with code like this:
await page.fill('input[name=mail]', 'playwright#example.com');
However, I'm getting an error:
=========================== logs ===========================
waiting for selector "input[name=mail]"
selector resolved to 2 elements. Proceeding with the first one.
selector resolved to hidden <input name="mail" type="email" placeholder="" autocorr…/>
elementHandle.fill("playwright#example.com")
waiting for element to be visible, enabled and editable
element is not visible - waiting...
The problem is that Playwright is seeing the first email address input on the login form, which is not visible, and then trying to fill that in instead of the visible email address input on the contact page.
Obviously, I never want to fill in an element that isn't visible, so how can I force playwright to only try to fill in visible elements?
You can use page.locator to check for visibility first and then fill in the value.
await page.locator('input[name=mail] >> visible=true').fill('playwright#example.com');
To make tests easier to write, wrap this in a helper function:
async fillFormElement(
inputType: 'input' | 'textarea',
name: string,
value: string,
) {
await this.page
.locator(`${inputType}[name=${name}] >> visible=true`)
.fill(value);
}
It can be done in this way, if you are trying to check is element visible. Even you have two same elements with one selector one hidden one visible.
const element = await page.waitForSelector(selector, {state:visible});
await element.fill(yourString);
I often use this site but it had never happened to me to ask a question. Now I am blocked and so it is time to ask the first one.
I need to test a sign up form created with vue 2 and vuetify, server side rendered with ruby on rails, webpack 5.
I configured capybara with selenium chrome headless driver, it works when it comes to interacting with text fields and buttons but when I try to check the checkbox:
(byebug) check('Accept')
*** Capybara::ElementNotFound Exception: Unable to find visible checkbox "Accept" that is not disabled
Vuetify hides the input and replaces it with beautiful div but, what is the best approach to check a v-checkbox?
Signup form
If I add the visible attribute, the input is found but nothing happens. I think I need to interact with some other element?
(byebug) check('Accept', visible: false)
#<Capybara::Node::Element tag="input" path="/HTML/BODY[1]/DIV[1]/DIV[1]/DIV[1]/MAIN[1]/DIV[1]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/FORM[1]/DIV[2]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/INPUT[1]">
I also tried this but still nothing happen:
(byebug) page.find('input[type=checkbox]', visible: false).set(true)
#<Capybara::Node::Element tag="input" path="/HTML/BODY[1]/DIV[1]/DIV[1]/DIV[1]/MAIN[1]/DIV[1]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/FORM[1]/DIV[2]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/INPUT[1]">
So I also tried the click way but getting this error:
(byebug) page.find('input[type=checkbox]', visible: false).click
*** Selenium::WebDriver::Error::ElementClickInterceptedError Exception: element click intercepted: Element <input aria-checked="false" id="input-96" role="checkbox" type="checkbox" value=""> is not clickable at point (234, 531). Other element would receive the click: <div class="v-input--selection-controls__ripple"></div>
(Session info: headless chrome=85.0.4183.121)
I tried also executing the raw script:
page.execute_script("window.uiApp.$data.terms_and_conditions = true")
The vue app is mounted in this way:
window.uiApp = new Vue({
i18n,
vuetify,
store,
router,
el: id,
render: h => h(App, {
props
})
})
But window.uiApp.$data is empty, so this attempt also seems to fail :( How to access vue component data (without vue web tool)?
I don't know what else to try, thanks in advance
Looking at the HTML shown in your linked image (in the future when asking questions it would be helpful if you included the relevant HTML directly in your question) it looks like you have a label associated with the hidden checkbox that the user can click. In that case you can use
check('Accept', allow_label_click: true)
which, when the actual checkbox is hidden, will click on the associated label instead. If you want that behavior to be on by default you can set Capybara.automatic_label_click = true.
Your other option is to determine exactly which element is actually being shown as the 'checkbox' and use find(...).click to locate that element and click on it.
I changed the checkbox in this way:
<v-checkbox v-model="terms_and_conditions"
#input='$v.terms_and_conditions.$touch()'
#blur='$v.terms_and_conditions.$touch()'
:label="$t('commons.accept')">
</v-checkbox>
<div class="ml-2">
<v-tooltip bottom>
<template v-slot:activator="{ on }">
<a
target="_blank"
href="/users/terms_and_conditions"
#click.stop
v-on="on"
>
{{ $t('session.sign_up.terms') }}
</a>
</template>
{{ $t('session.sign_up.terms_hint') }}
</v-tooltip>
</div>
Thank you
I'm trying to figure out how I can ReactiveList to display a related searches feature on the results page. It seems that my es app on appbaseio keeps adding links EVEN after the page has sat idle for a few minutes, NO USER INTERACTION at all.
This is my code for the ReativeList component
<ReactiveList
componentId="related-searches"
pages={1}
size={5}
stream={false}
showResultStats={false}
react={{
"and": ["SearchSensor"]
}}
onData={(res) => <a href="#" className="card-link"><li
className="list-inline-item">Link text</li></a>}
/>
I thought that pages, size and stream (and their settings) would stop the streaming (or whatever is causing it)?
You can use the defaultQuery prop on ReactiveList to make it show some default results (or related searches in your case) docs. For example:
<ReactiveList
...
defaultQuery={() => ({
match: {
authors: 'J.K. Rowling'
}
})}
/>
Demo
I'm working with an existing Rails app where the navigation must continue to be constructed on the backend (due to complexity and time limitations). The intended result is to have some of the pages generated with Elm, and some with Rails, using no hashes, and no full page reloads (at least for the Elm pages). The simplified version of the navigation looks like this:
<nav>
<a href="rails-page-1">...
<a href="rails-page-2">...
<a href="elm-page-1">...
<a href="elm-page-2">...
</nav>
<div id="elm-container"></div>
I've experimented with the Elm navigation package, and the elm-route-url, possibly coming close with the latter unless I'm fundamentally misunderstanding the package's capability.
Is there a way to accomplish this? I've gotten it working using hash tags, but no luck without them.
using hash tags
Well you got a chuckle out of me.
I have this guy in my Helpers.elm file that I can use in lieu of Html.Events.click.
{-| Useful for overriding the default `<a>` behavior which
causes a refresh, but can be used anywhere
-}
overrideClick : a -> Attribute a
overrideClick =
Decode.succeed
>> onWithOptions "click"
{ stopPropagation = False
, preventDefault = True
}
So on an a [ overrideClick (NavigateTo "/route"), href "/route" ] [ text "link" ] which would allow middle-clicking the element as well as using push state to update the navigation.
What you're needing is something similar on the JavaScript that works with pushState, and you don't want to ruin the middle-click experience. You can hijack all <a>s,preventDefault on its event to stop the browser from navigating, and push in the new state via the target's href. You can delegate the navigation's <a>s in the event handler. Since the Navigation runtime doesn't support listening to history changes externally (rather it appears to be using an effect manager), you'll have to push the value through a port -- luckily if you're using the Navigation package, you should already have the pieces.
On the Elm end, use UrlParser.parsePath in conjuction with one of the Navigation programs. Create a port to subscribe to using the same message that is used for it's internal url changes.
import Navigation exposing (Location)
port externalPush : (Location -> msg) -> Sub msg
type Msg
= UrlChange Location
| ...
main =
Navigation.program UrlChange
{ ...
, subscriptions : \_ -> externalPush UrlChange
}
After the page load, use this:
const hijackNavClick = (event) => {
// polyfill `matches` if needed
if (event.target.matches("a[href]")) {
// prevent the browser navigation
event.preventDefault()
// push the new url
window.history.pushState({}, "", event.target.href)
// send the new location into the Elm runtime via port
// assuming `app` is the name of `Elm.Main.embed` or
// whatever
app.ports.externalPush.send(window.location)
}
}
// your nav selector here
const nav = document.querySelector("nav")
nav.addEventListener("click", hijackNavClick, false)
I have next problem, when user looks to the filled form element xforms:select shown as it should be readonly and displays the label of selected item, below is html represenation of the element as it comes to browser
...
<span
id="control-8-control"
class="xforms-control xforms-select xforms-incremental xforms-select-appearance-full xforms-static xforms-readonly"
>
some value1
</span>
...
, but when user clicks on the text "some value", this texts turns to value of selected item, and looks next way
...
<span
id="control-8-control"
class="xforms-control xforms-select xforms-incremental xforms-select-appearance-full xforms-static xforms-readonly"
>
2WPbzcoW3eoH/1rDCyejaA==
</span>
...
Obviously some listener is hanging on that element, and changes it's inner-html.
Moreover this behavior can be observed only for xforms:select elements with appearance="full"
Where can I reconfigure this element behavior?
This is a bug. I didn't reproduce exactly the same problem you had, as I have been testing this on a nightly build, but most likely, the source of the problem is the same: the client sends a value change to the server when you click on the label, while it shouldn't. I fixed this, and the fix will be in the next nightly build. For reference, this is the bug and commit.