diff --git a/vividus-plugin-web-app-playwright/src/main/java/org/vividus/ui/web/playwright/action/PlaywrightJavascriptActions.java b/vividus-plugin-web-app-playwright/src/main/java/org/vividus/ui/web/playwright/action/PlaywrightJavascriptActions.java index 2e690028f1..f49813f831 100644 --- a/vividus-plugin-web-app-playwright/src/main/java/org/vividus/ui/web/playwright/action/PlaywrightJavascriptActions.java +++ b/vividus-plugin-web-app-playwright/src/main/java/org/vividus/ui/web/playwright/action/PlaywrightJavascriptActions.java @@ -17,12 +17,19 @@ package org.vividus.ui.web.playwright.action; import java.util.List; +import java.util.regex.Pattern; + +import com.microsoft.playwright.Page; import org.vividus.ui.web.action.JavascriptActions; import org.vividus.ui.web.playwright.UiContext; public class PlaywrightJavascriptActions implements JavascriptActions { + private static final Pattern PLAYWRIGHT_DECORATED_PATTERN = Pattern.compile("^(?:async\\s*)?" + + "(?:\\(\\s*(?:\\{[^}]*\\}|\\[[^\\]]*\\]|[^,()]+(?:,\\s*[^,()]+)?)?\\s*\\)|[^()\\s]+)\\s*" + + "=>\\s*(?:.|\\{|\\n)"); + private final UiContext uiContext; public PlaywrightJavascriptActions(UiContext uiContext) @@ -34,10 +41,21 @@ public PlaywrightJavascriptActions(UiContext uiContext) @Override public T executeScript(String script, Object... args) { - if (args.length == 0) - { - return (T) uiContext.getCurrentPage().evaluate("async () => {%n%s%n}".formatted(script)); - } - return (T) uiContext.getCurrentPage().evaluate(script, List.of(args)); + boolean hasArgs = args.length > 0; + String playwrightScript = isPlaywrightDecorated(script) ? script : decorateScript(script, hasArgs); + Page currentPage = uiContext.getCurrentPage(); + return (T) (hasArgs ? currentPage.evaluate(playwrightScript, List.of(args)) + : currentPage.evaluate(playwrightScript)); + } + + private boolean isPlaywrightDecorated(String script) + { + return PLAYWRIGHT_DECORATED_PATTERN.matcher(script).find(); + } + + private String decorateScript(String script, boolean hasArgs) + { + String playwrightFormat = hasArgs ? "arguments => {%n%s%n}" : "async () => {%n%s%n}"; + return playwrightFormat.formatted(script); } } diff --git a/vividus-plugin-web-app-playwright/src/test/java/org/vividus/ui/web/playwright/action/PlaywrightJavascriptActionsTests.java b/vividus-plugin-web-app-playwright/src/test/java/org/vividus/ui/web/playwright/action/PlaywrightJavascriptActionsTests.java index cda044901e..7cdd2ad2cb 100644 --- a/vividus-plugin-web-app-playwright/src/test/java/org/vividus/ui/web/playwright/action/PlaywrightJavascriptActionsTests.java +++ b/vividus-plugin-web-app-playwright/src/test/java/org/vividus/ui/web/playwright/action/PlaywrightJavascriptActionsTests.java @@ -26,6 +26,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -35,6 +37,8 @@ class PlaywrightJavascriptActionsTests { private static final String JS_SCRIPT = "document.querySelector('[name=\"vividus-logo\"]').remove()"; + private static final String NO_ARGS_FORMAT = "async () => {%n%s%n}"; + private static final String ARGS_FORMAT = "arguments => {%n%s%n}"; @Mock private UiContext uiContext; @InjectMocks private PlaywrightJavascriptActions playwrightJavascriptActions; @@ -45,17 +49,44 @@ void shouldExecuteScript() var page = mock(Page.class); when(uiContext.getCurrentPage()).thenReturn(page); playwrightJavascriptActions.executeScript(JS_SCRIPT); - verify(page).evaluate("async () => {%n%s%n}".formatted(JS_SCRIPT)); + verify(page).evaluate(NO_ARGS_FORMAT.formatted(JS_SCRIPT)); } @Test void shouldExecuteScriptWithArgument() { var page = mock(Page.class); - var script = "script"; var arg = "arg"; when(uiContext.getCurrentPage()).thenReturn(page); - playwrightJavascriptActions.executeScript(script, arg); - verify(page).evaluate(script, List.of(arg)); + playwrightJavascriptActions.executeScript(JS_SCRIPT, arg); + verify(page).evaluate(ARGS_FORMAT.formatted(JS_SCRIPT), List.of(arg)); + } + + @ParameterizedTest + @ValueSource(strings = { + "num => num", + "object => object.foo", + "(button, from) => button.textContent.substring(from)", + "(button, from ) => button.textContent.substring(from)", + "( button, from) => button.textContent.substring(from)", + "(button,from) => button.textContent.substring(from)", + "o => o.button1.textContent + o.button2.textContent", + "({button1, button2}) => button1.textContent + button2.textContent", + "({ button1, button2 }) => button1.textContent + button2.textContent", + "( {button1, button2} ) => button1.textContent + button2.textContent", + "( { button1, button2 } ) => button1.textContent + button2.textContent", + "([b1, b2]) => b1.textContent + b2.textContent", + "( [b1, b2] ) => b1.textContent + b2.textContent", + "( [ b1, b2 ] ) => b1.textContent + b2.textContent", + "x => x.button1.textContent + x.list[0].textContent + String(x.foo)", + "() => {\\n const response = (() => asd) await fetch(location.href);\\n return response.status;\\n}", + "async () => {\\n const response = (() => asd) await fetch(location.href);\\n return response.status;\\n}" + }) + void shouldNotDecorateScript(String script) + { + var page = mock(Page.class); + when(uiContext.getCurrentPage()).thenReturn(page); + playwrightJavascriptActions.executeScript(script); + verify(page).evaluate(script); } }