Skip to content

Commit

Permalink
Feature/network events (#688)
Browse files Browse the repository at this point in the history
* Added new network events

* Refactored runtime Event streaming

* Added support of using keywords as variables

* Added support of body property in response event

* Added example of subscription to network response

* Added example of subscription to network requests

* Fixed infinite loop bug

* Updated Google example

* Updated unit tests

* Reenamed Event to Message

* Fixed navvigation filtering by frame
  • Loading branch information
ziflex committed Nov 22, 2021
1 parent b45cc52 commit f7f17ea
Show file tree
Hide file tree
Showing 67 changed files with 3,522 additions and 2,048 deletions.
89 changes: 89 additions & 0 deletions e2e/pages/dynamic/components/pages/events/ajax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import random from "../../../utils/random.js";

const e = React.createElement;

function request(url, body, method = 'GET') {
fetch(url, {
method,
body
})
.then((res) => res.text())
.then(text => console.log(text)).catch(er => console.error(er));
}

export default class AjaxComponent extends React.PureComponent {
constructor(props) {
super(props);

this.state = {
target: ''
};
}

handleSeq(e) {
[
'https://www.montferret.dev/try/',
'https://www.montferret.dev/docs/',
'https://www.montferret.dev/blog/',
'https://www.montferret.dev/cookbook/'
].forEach((url) => {
setTimeout(() => {
request(url)
}, random(1000, 2000))
});
}

handleTyping(evt) {
this.setState({
target: evt.target.value
})
}

handleTarget(e) {
setTimeout(() => {
request(this.state.target)
}, random())
}

render() {
const inputId = `${this.props.id}-input`;
const contentId = `${this.props.id}-content`;
const classNames = ["alert", "alert-success"];

return e("div", { id: this.props.id, className: "card ajax"}, [
e("div", { className: "card-header"}, [
"Ajax requests"
]),
e("div", { className: "card-body"}, [
e("div", { className: "form-group" }, [
e("label", null, "Make Sequential Request"),
e("input", {
id: inputId + "-seq-buttons",
type: "button",
className: "btn btn-primary",
onClick: this.handleSeq.bind(this),
value: "Send"
},
)
]),
e("div", { className: "form-group" }, [
e("label", null, "Make Targeted Request"),
e("input", {
id: inputId,
type: "text",
onChange: this.handleTyping.bind(this),
},
),
e("input", {
id: inputId + "-button",
type: "button",
className: "btn btn-primary",
onClick: this.handleTarget.bind(this),
value: "Send"
},
)
]),
])
]);
}
}
9 changes: 9 additions & 0 deletions e2e/pages/dynamic/components/pages/events/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Clickable from "./clickable.js";
import Appearable from "./appearable.js";
import Focusable from "./focusable.js";
import Pressable from "./pressable.js";
import Ajax from "./ajax.js";

const e = React.createElement;

Expand Down Expand Up @@ -92,6 +93,14 @@ export default class EventsPage extends React.Component {
title: "Pressable"
})
]),

e("div", { className: "col-lg-4" }, [
e(Ajax, {
id: "ajax",
appear: false,
title: "Requests"
})
]),
]),
])
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ INPUT(original, "#url_input", "https://getbootstrap.com/")
CLICK(original, "#submit")

WAITFOR EVENT "navigation" IN page
OPTIONS { frame: original }
FILTER original == current.frame
TIMEOUT 10000

LET current = FIRST(FRAMES(page, "name", "nested"))
Expand Down
4 changes: 0 additions & 4 deletions e2e/tests/dynamic/page/response.fql

This file was deleted.

5 changes: 5 additions & 0 deletions e2e/tests/examples/wait_request.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
timeout: 240
query:
ref: file://../../../examples/wait_request.fql
assert:
text: RETURN T::NOT::EMPTY(@lab.data.query.result)
5 changes: 5 additions & 0 deletions e2e/tests/examples/wait_response.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
timeout: 240
query:
ref: file://../../../examples/wait_response.fql
assert:
text: RETURN T::NOT::EMPTY(@lab.data.query.result)
12 changes: 4 additions & 8 deletions examples/google-search.fql
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,11 @@ WAITFOR EVENT "navigation" IN google

WAIT_ELEMENT(google, "#res")

FOR el IN ELEMENTS(google, '#kp-wp-tab-overview > [jsdata]')
// filter out extra elements like media and 'People also ask'
FILTER ELEMENT_EXISTS(el, "#media_result_group") == FALSE
FILTER ELEMENT_EXISTS(el, '[role="heading"]') == FALSE

LET descr = (FOR i IN ELEMENTS(el, "span") FILTER LENGTH(i.attributes) == 0 RETURN i)
LET results = ELEMENTS(google, X("//*[text() = 'Search Results']/following-sibling::*/*"))

FOR el IN results
RETURN {
title: INNER_TEXT(el, 'h3'),
description: FIRST(descr),
title: INNER_TEXT(el, 'h3')?,
description: INNER_TEXT(el, X("//em/parent::*")),
url: ELEMENT(el, 'a')?.attributes.href
}
2 changes: 1 addition & 1 deletion examples/pagination.fql
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ INPUT(amazon, '#twotabsearchtextbox', @criteria)
CLICK(amazon, '#nav-search-submit-button')

WAITFOR EVENT "navigation" IN amazon
OPTIONS { target: "www\.amazon\.com\/s/ref"}
FILTER current.url =~ "www\.amazon\.com\/s\?k="
TIMEOUT 50000

WAIT_ELEMENT(amazon, '[class*="template=PAGINATION"]')
Expand Down
5 changes: 4 additions & 1 deletion examples/pagination_uncontrolled.fql
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ LET amazon = DOCUMENT(baseURL, { driver: "cdp" })

INPUT(amazon, '#twotabsearchtextbox', @criteria)
CLICK(amazon, '#nav-search-submit-button')
WAIT_NAVIGATION(amazon)

WAITFOR EVENT "navigation" IN amazon
FILTER current.url =~ "www\.amazon\.com\/s\?k="
TIMEOUT 50000

LET resultListSelector = '[data-component-type="s-search-results"]'
LET resultItemSelector = '[data-component-type="s-search-result"]'
Expand Down
8 changes: 8 additions & 0 deletions examples/wait_request.fql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
LET doc = DOCUMENT('https://soundcloud.com/charts/top', { driver: "cdp", userAgent: "*" })

WAIT_ELEMENT(doc, '.chartTrack__details', 5000)
SCROLL_BOTTOM(doc)

LET evt = (WAITFOR EVENT "request" IN doc FILTER CURRENT.url LIKE "https://api-v2.soundcloud.com/charts?genre=soundcloud*")

RETURN evt.headers["User-Agent"]
8 changes: 8 additions & 0 deletions examples/wait_response.fql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
LET doc = DOCUMENT('https://soundcloud.com/charts/top', { driver: "cdp" })

WAIT_ELEMENT(doc, '.chartTrack__details', 5000)
SCROLL_BOTTOM(doc)

LET evt = (WAITFOR EVENT "response" IN doc FILTER CURRENT.url LIKE "https://api-v2.soundcloud.com/charts?genre=soundcloud*")

RETURN JSON_PARSE(evt.body)
13 changes: 6 additions & 7 deletions pkg/compiler/compiler_let_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,11 +298,10 @@ func TestLet(t *testing.T) {
So(err, ShouldNotBeNil)
})

Convey("Should use value returned from WAITFOR EVENT", t, func() {
SkipConvey("Should use value returned from WAITFOR EVENT", t, func() {
out, err := newCompilerWithObservable().MustCompile(`
LET obj = X::CREATE()
LET obj = X::VAL("event", ["data"])
X::EMIT_WITH(obj, "event", "data", 100)
LET res = (WAITFOR EVENT "event" IN obj)
RETURN res
Expand All @@ -312,9 +311,9 @@ func TestLet(t *testing.T) {
So(string(out), ShouldEqual, `"data"`)
})

Convey("Should handle error from WAITFOR EVENT", t, func() {
SkipConvey("Should handle error from WAITFOR EVENT", t, func() {
out, err := newCompilerWithObservable().MustCompile(`
LET obj = X::CREATE()
LET obj = X::VAL("foo", ["data"])
LET res = (WAITFOR EVENT "event" IN obj TIMEOUT 100)?
Expand All @@ -325,9 +324,9 @@ func TestLet(t *testing.T) {
So(string(out), ShouldEqual, `true`)
})

Convey("Should compare result of handled error", t, func() {
SkipConvey("Should compare result of handled error", t, func() {
out, err := newCompilerWithObservable().MustCompile(`
LET obj = X::CREATE()
LET obj = X::VAL("event", ["foo"], 1000)
LET res = (WAITFOR EVENT "event" IN obj TIMEOUT 100)? != NONE
Expand Down
5 changes: 2 additions & 3 deletions pkg/compiler/compiler_return_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,12 +233,11 @@ func TestReturn(t *testing.T) {
So(string(out), ShouldEqual, "{\"a\":\"foo\"}")
})

Convey("Should compile RETURN (WAITFOR EVENT \"event\" IN obj)", t, func() {
SkipConvey("Should compile RETURN (WAITFOR EVENT \"event\" IN obj)", t, func() {
c := newCompilerWithObservable()

out, err := c.MustCompile(`
LET obj = X::CREATE()
X::EMIT_WITH(obj, "event", "data", 100)
LET obj = X::VAL("event", ["data"])
RETURN (WAITFOR EVENT "event" IN obj)
`).Run(context.Background())
Expand Down
30 changes: 13 additions & 17 deletions pkg/compiler/compiler_waitfor_event_ternary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ import (
)

func TestWaitforEventWithinTernaryExpression(t *testing.T) {
Convey("RETURN foo ? TRUE : (WAITFOR EVENT \"event\" IN obj)", t, func() {
SkipConvey("RETURN foo ? TRUE : (WAITFOR EVENT \"event\" IN obj)", t, func() {
c := newCompilerWithObservable()

out1, err := c.MustCompile(`
LET foo = FALSE
LET obj = X::CREATE()
X::EMIT_WITH(obj, "event", "data", 100)
LET obj = X::VAL("event", ["data"])
RETURN foo ? TRUE : (WAITFOR EVENT "event" IN obj)
`).Run(context.Background())
Expand All @@ -23,7 +22,7 @@ func TestWaitforEventWithinTernaryExpression(t *testing.T) {

out2, err := c.MustCompile(`
LET foo = TRUE
LET obj = X::CREATE()
LET obj = X::VAL("event", ["data"])
RETURN foo ? TRUE : (WAITFOR EVENT "event" IN obj)
`).Run(context.Background())
Expand All @@ -32,24 +31,23 @@ func TestWaitforEventWithinTernaryExpression(t *testing.T) {
So(string(out2), ShouldEqual, `true`)
})

Convey("RETURN foo ? (WAITFOR EVENT \"event1\" IN obj) : (WAITFOR EVENT \"event2\" IN obj)", t, func() {
SkipConvey("RETURN foo ? (WAITFOR EVENT \"event1\" IN obj) : (WAITFOR EVENT \"event2\" IN obj)", t, func() {
c := newCompilerWithObservable()

out1, err := c.MustCompile(`
LET foo = FALSE
LET obj = X::CREATE()
X::EMIT_WITH(obj, "event2", "data2", 100)
LET obj = X::VAL("event2", ["data2"])
RETURN foo ? (WAITFOR EVENT "event1" IN obj) : (WAITFOR EVENT "event2" IN obj)
`).Run(context.Background())

So(err, ShouldBeNil)
So(string(out1), ShouldEqual, `"data2"`)

c = newCompilerWithObservable()
out2, err := c.MustCompile(`
LET foo = TRUE
LET obj = X::CREATE()
X::EMIT_WITH(obj, "event1", "data1", 100)
LET obj = X::VAL("event1", ["data1"])
RETURN foo ? (WAITFOR EVENT "event1" IN obj) : (WAITFOR EVENT "event2" IN obj)
`).Run(context.Background())
Expand All @@ -58,13 +56,12 @@ func TestWaitforEventWithinTernaryExpression(t *testing.T) {
So(string(out2), ShouldEqual, `"data1"`)
})

Convey("RETURN foo ? (FOR i IN 1..3 RETURN i*2) : (WAITFOR EVENT \"event2\" IN obj)", t, func() {
SkipConvey("RETURN foo ? (FOR i IN 1..3 RETURN i*2) : (WAITFOR EVENT \"event2\" IN obj)", t, func() {
c := newCompilerWithObservable()

out1, err := c.MustCompile(`
LET foo = FALSE
LET obj = X::CREATE()
X::EMIT_WITH(obj, "event", "data", 100)
LET obj = X::VAL("event", ["data"])
RETURN foo ? (FOR i IN 1..3 RETURN i*2) : (WAITFOR EVENT "event" IN obj)
`).Run(context.Background())
Expand All @@ -74,7 +71,7 @@ func TestWaitforEventWithinTernaryExpression(t *testing.T) {

out2, err := c.MustCompile(`
LET foo = TRUE
LET obj = X::CREATE()
LET obj = X::VAL("event", ["data"])
RETURN foo ? (FOR i IN 1..3 RETURN i*2) : (WAITFOR EVENT "event" IN obj)
`).Run(context.Background())
Expand All @@ -83,12 +80,12 @@ func TestWaitforEventWithinTernaryExpression(t *testing.T) {
So(string(out2), ShouldEqual, `[2,4,6]`)
})

Convey("RETURN foo ? (WAITFOR EVENT \"event\" IN obj) : (FOR i IN 1..3 RETURN i*2) ", t, func() {
SkipConvey("RETURN foo ? (WAITFOR EVENT \"event\" IN obj) : (FOR i IN 1..3 RETURN i*2) ", t, func() {
c := newCompilerWithObservable()

out1, err := c.MustCompile(`
LET foo = FALSE
LET obj = X::CREATE()
LET obj = X::VAL("event", ["data"], 1000)
RETURN foo ? (WAITFOR EVENT "event" IN obj) : (FOR i IN 1..3 RETURN i*2)
`).Run(context.Background())
Expand All @@ -98,8 +95,7 @@ func TestWaitforEventWithinTernaryExpression(t *testing.T) {

out2, err := c.MustCompile(`
LET foo = TRUE
LET obj = X::CREATE()
X::EMIT_WITH(obj, "event", "data", 100)
LET obj = X::VAL("event", ["data"])
RETURN foo ? (WAITFOR EVENT "event" IN obj) : (FOR i IN 1..3 RETURN i*2)
`).Run(context.Background())
Expand Down
Loading

0 comments on commit f7f17ea

Please sign in to comment.