GithubHelp home page GithubHelp logo

Comments (10)

jan-molak avatar jan-molak commented on June 13, 2024 2

Serenity/JS interactions that accept custom configuration or overrides typically have a .using(configuration) method. For example:

await actor.attemptsTo(
  Send.a(GetRequest.to('/books/0-688-00230-7').using({ headers: { ... } }),
)

You might want to consider something like this:

Scroll.to(pageElement).using(configuration)

However, some differences between WebdriverIO, Protractor and Playwright might make deciding how this interaction should behave tricky.

For example:

Another interesting challenge is that the element.scrollIntoView API is not particularly well designed as it allows either a boolean or a configuration object (instead of just the configuration object).

Following that design could make Serenity/JS interaction look awkward:

Scroll.to(pageElement).using(true) // meh

However, since true is really just an alias for {block: "start", inline: "nearest"} and false means scrollIntoViewOptions: {block: "end", inline: "nearest"}, we could have some pre-set configurations to make people's lives easier:

Scroll.to(pageElement).using(Scroll.Top)
// where Scroll.Top == `{block: "start", inline: "nearest"}`

Alternatively, we could have alias methods on Scroll itself:

Scroll.toTopOf(pageElement)
// alias for Scroll.to(pageElement).using({block: "start", inline: "nearest"})

from serenity-js.

jan-molak avatar jan-molak commented on June 13, 2024 2

Click relies on whatever a given web integration tool considers the "default scrolling behaviour". If you'd like to use a different behaviour, then you could introduce custom interactions and then compose them into a task:

const MyClick = (pageElement: Answerable<PageElement>) =>
  Interaction.where(d`#actor clicks on ${pageElement}`, async actor => {
    const element = await actor.answer(pageElement);
    // note no scrolling
    await element.click();
  })

const MyScrollAndClick = (element: Answerable<PageElement>) => 
  Task.where(d`#actor clicks on ${ element }`,
    Scroll.toCentreOf(element), // as discussed previously
    MyClick(element),
  )

Another alternative is to:

  • make the scrolling behaviour of the built-in Click configurable
  • override the default behaviour of web integration tools to provide different defaults
  • or remove scrolling behaviour from Click altogether, relying instead on developers to add Scroll when needed

from serenity-js.

jan-molak avatar jan-molak commented on June 13, 2024 1

Certainly, you can use script injection:

import { Answerable, d, Interaction } from '@serenity-js/core'
import { BrowseTheWeb, PageElement } from '@serenity-js/web'

const ScrollToTopOf = (pageElement: Answerable<PageElement>) =>
  Interaction.where(d`#actor scrolls to top of ${ pageElement }`, async actor => {
    const element = await actor.answer(pageElement);
    const page = await BrowseTheWeb.as(actor).currentPage();

    await page.executeScript(
      function scrollIntoView(nativeElement: any) {
        nativeElement.scrollIntoView({block: "start", inline: "nearest"});
      },
      element,
    )
  })

from serenity-js.

jan-molak avatar jan-molak commented on June 13, 2024 1

Sorry, it was a typo; I've updated the original snippet.
As you can see there, I use Page.executeScript to inject a function that then calls the native scrollIntoView, which you can parameterise as per the MDN docs.

from serenity-js.

Himanshu21git avatar Himanshu21git commented on June 13, 2024 1

Click relies on whatever a given web integration tool considers the "default scrolling behaviour". If you'd like to use a different behaviour, then you could introduce custom interactions and then compose them into a task:

const MyClick = (pageElement: Answerable<PageElement>) =>
  Interaction.where(d`#actor clicks on ${pageElement}`, async actor => {
    const element = await actor.answer(pageElement);
    // note no scrolling
    await element.click();
  })

const MyScrollAndClick = (element: Answerable<PageElement>) => 
  Task.where(d`#actor clicks on ${ element }`,
    Scroll.toCentreOf(element), // as discussed previously
    MyClick(element),
  )

Another alternative is to:

  • make the scrolling behaviour of the built-in Click configurable
  • override the default behaviour of web integration tools to provide different defaults
  • or remove scrolling behaviour from Click altogether, relying instead on developers to add Scroll when needed

Yes, it works. Thanks @jan-molak 😄

from serenity-js.

jan-molak avatar jan-molak commented on June 13, 2024

I like this idea! However, some differences across the supported web integration tools make the implementation a bit more challenging.

You can see the first attempt at implementing this feature at #1235

Happy to guide you through raising a PR if this feature is something you'd like to pick up.

from serenity-js.

Himanshu21git avatar Himanshu21git commented on June 13, 2024

Indeed, I'm interested in working on this. I would greatly appreciate your guidance in creating a custom interaction that mirrors the Click activity. This will allow me to explore and experiment with the scrollIntoView behavior within this custom activity, which I'll refer to as "CustomClick."

from serenity-js.

Himanshu21git avatar Himanshu21git commented on June 13, 2024

Hi @jan-molak,
While I'm currently working on this, could you propose an alternative solution for this issue, specially tailored for a Serenity + Webdriverio setup? I'm in the process of implementing Serenity/JS in one of my projects, and I've encountered an issue with the scrollIntoView method used within the Click interaction.

The problem is that scrollIntoView places the target element at the top of the page. Consequently, the element I want to click on gets positioned behind a navigation bar, and the click action is intercepted by two overlapping elements.

from serenity-js.

Himanshu21git avatar Himanshu21git commented on June 13, 2024

Certainly, you can use script injection:

import { Answerable, d, Interaction } from '@serenity-js/core'
import { BrowseTheWeb, PageElement } from '@serenity-js/web'

const ScrollToTopOf = (pageElement: Answerable<PageElement>) =>
  Interaction.where(d`#actor scrolls to top of ${ pageElement }`, async actor => {
    const element = await actor.answer(pageElement);
    const page = await BrowseTheWeb.as(actor).currentPage();

    await page.executeScript(
      function scrollIntoView(element: any) {
        element.scrollIntoView({block: "start", inline: "nearest"});
      },
      await field,
    )
  })

@jan-molak Would you mind providing clarification regarding the term 'field' in the code snippet you shared? My goal is to ensure that when the scrollIntoView method is employed, the element is centered within the viewport.

from serenity-js.

Himanshu21git avatar Himanshu21git commented on June 13, 2024

However, @jan-molak , this approach won't be sufficient for overriding the scrollIntoView() method used within the Click interaction. How can I address this? As you can observe from the source code of the Click Interaction here:

class Click extends PageElementInteraction_1.PageElementInteraction {
    /**
     * Instantiates this Interaction.
     *
     * @param pageElement
     *  The element to be clicked on
     */
    static on(pageElement) {
        return new Click(pageElement);
    }
    constructor(element) {
        super((0, core_1.d) `#actor clicks on ${element}`);
        this.element = element;
    }
    /**
     * @inheritDoc
     */
    async performAs(actor) {
        const element = await this.resolve(actor, this element);

        await element.scrollIntoView();  // I'm interested in customizing this scrolling behavior within the Click interaction
        await element.click();
    }
}

In this code, I'd like to emphasize my intent to customize the scrolling behavior within the Click interaction, which is not achievable using the previous approach. How should I proceed?

from serenity-js.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.