diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b73f543..21043acb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ #### Fixed - Scrolling position is not centered. [#343](https://github.com/MontFerret/ferret/pull/343) - Unable to set custom logger fields. [#346](https://github.com/MontFerret/ferret/pull/346) +- Fixed ``INNER_HTML``, ``INNER_TEXT``, ``INNER_HTML_SET``, ``INNER_TEXT_SET`` functions. [#347](https://github.com/MontFerret/ferret/pull/347) - Unable to set custom headers. [#348](https://github.com/MontFerret/ferret/pull/348) ### 0.8.1 diff --git a/Makefile b/Makefile index e43d1599..b5d46b2b 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ cover: e2e: go run ${DIR_E2E}/main.go --tests ${DIR_E2E}/tests --pages ${DIR_E2E}/pages - # --filter=e2e/tests/**/xpath/*.fql + # --filter=e2e/tests/dynamic/element/inner_text/get_by_selector.fql bench: go test -run=XXX -bench=. ${DIR_PKG}/... diff --git a/e2e/pages/dynamic/components/app.js b/e2e/pages/dynamic/components/app.js index ff73d159..b703c2af 100644 --- a/e2e/pages/dynamic/components/app.js +++ b/e2e/pages/dynamic/components/app.js @@ -5,6 +5,7 @@ import EventsPage from './pages/events/index.js'; import IframePage from './pages/iframes/index.js'; import MediaPage from './pages/media/index.js'; import PaginationPage from './pages/pagination/index.js'; +import ListsPage from './pages/lists/index.js'; const e = React.createElement; const Router = ReactRouter.Router; @@ -61,6 +62,10 @@ export default React.memo(function AppComponent(params = {}) { path: '/pagination', component: PaginationPage }), + e(Route, { + path: '/lists', + component: ListsPage + }), ]), redirectTo ]) diff --git a/e2e/pages/dynamic/components/pages/lists/index.js b/e2e/pages/dynamic/components/pages/lists/index.js new file mode 100644 index 00000000..9284eec9 --- /dev/null +++ b/e2e/pages/dynamic/components/pages/lists/index.js @@ -0,0 +1,20 @@ +const e = React.createElement; + +const ITEMS = [{"artist":"Lil Tecca","track":"Ransom"},{"artist":"NLE Choppa","track":"Shotta Flow (Feat. Blueface) [Remix]"},{"artist":"Baby Jesus (DaBaby)","track":"Suge"},{"artist":"NLE Choppa","track":"Shotta Flow 3"},{"artist":"Lil Tecca ","track":"Lil Tecca - Did It Again"},{"artist":"NLE Choppa","track":"Shotta Flow"},{"artist":"Ynw Melly","track":"Dangerously In Love (772 Love Pt. 2)"},{"artist":"POLO G","track":"Polo G feat. Lil TJay - Pop Out"},{"artist":"MUSTARD","track":"Ballin' (feat. Roddy Ricch)"},{"artist":"Lil Nas X","track":"Panini"},{"artist":"Juice WRLD","track":"Juice Wrld - RUN"},{"artist":"Shordie Shordie","track":"Betchua (Bitchuary)"},{"artist":"Post Malone","track":"Goodbyes (feat. Young Thug)"},{"artist":"LIL UZI VERT","track":"Sanguine Paradise"},{"artist":"Calboy","track":"Envy Me"},{"artist":"Ambjaay","track":"Uno"},{"artist":"Lil Tecca","track":"Lil Tecca - Bossanova"},{"artist":"Lil Baby","track":"Baby"},{"artist":"Lil Tjay","track":"Lil Tjay - Brothers (Prod by JDONTHATRACK & Protegebeatz)"},{"artist":"YK Osiris","track":"Worth It"}]; + +export default class ListsPage extends React.Component { + render() { + const items = ITEMS.map((i) => { + return e("li", { className: "list-group-item track"}, [ + e("div", { className: "track-details"}, [ + e("h5", { className: "track-artist"}, i.artist), + e("small", { className: "track-name"}, i.track) + ]) + ]) + }); + + return e("div", { id: "tracks" }, [ + e("ul", { className: "list-group track-list" }, items) + ]) + } +} \ No newline at end of file diff --git a/e2e/tests/dynamic/element/inner_html/get_by_selector.fql b/e2e/tests/dynamic/element/inner_html/get_by_selector.fql index 3ee88477..f07dd48b 100644 --- a/e2e/tests/dynamic/element/inner_html/get_by_selector.fql +++ b/e2e/tests/dynamic/element/inner_html/get_by_selector.fql @@ -1,11 +1,34 @@ -LET url = @dynamic +LET url = @dynamic + "/#/lists" LET doc = DOCUMENT(url, true) -LET el = ELEMENT(doc, ".jumbotron") -LET expected = `Welcome to Ferret E2E test page!` -LET actual = INNER_HTML(el, "h1") +LET expected = [ + {"details":'
Lil Tecca
Ransom'}, + {"details":'
NLE Choppa
Shotta Flow (Feat. Blueface) [Remix]'}, + {"details":'
Baby Jesus (DaBaby)
Suge'}, + {"details":'
NLE Choppa
Shotta Flow 3'}, + {"details":'
Lil Tecca
Lil Tecca - Did It Again'}, + {"details":'
NLE Choppa
Shotta Flow'}, + {"details":'
Ynw Melly
Dangerously In Love (772 Love Pt. 2)'}, + {"details":'
POLO G
Polo G feat. Lil TJay - Pop Out'}, + {"details":`
MUSTARD
Ballin' (feat. Roddy Ricch)`}, + {"details":'
Lil Nas X
Panini'}, + {"details":'
Juice WRLD
Juice Wrld - RUN'}, + {"details":'
Shordie Shordie
Betchua (Bitchuary)'}, + {"details":'
Post Malone
Goodbyes (feat. Young Thug)'}, + {"details":'
LIL UZI VERT
Sanguine Paradise'}, + {"details":'
Calboy
Envy Me'}, + {"details":'
Ambjaay
Uno'}, + {"details":'
Lil Tecca
Lil Tecca - Bossanova'}, + {"details":'
Lil Baby
Baby'}, + {"details":'
Lil Tjay
Lil Tjay - Brothers (Prod by JDONTHATRACK & Protegebeatz)'}, + {"details":'
YK Osiris
Worth It'} +] -LET r1 = '(\n|\s)' -LET r2 = '(\n|\s)' +LET actual = ( + FOR item IN ELEMENTS(doc, '.track-list li') + RETURN { + details: INNER_HTML(item, '.track-details'), + } +) -RETURN EXPECT(REGEXP_REPLACE(expected, r1, ''), REGEXP_REPLACE(TRIM(actual), r2, '')) \ No newline at end of file +RETURN EXPECT(expected, actual) \ No newline at end of file diff --git a/e2e/tests/dynamic/element/inner_html/set_by_selector.fql b/e2e/tests/dynamic/element/inner_html/set_by_selector.fql new file mode 100644 index 00000000..267ffcd8 --- /dev/null +++ b/e2e/tests/dynamic/element/inner_html/set_by_selector.fql @@ -0,0 +1,25 @@ +LET url = @dynamic + "/#/lists" +LET doc = DOCUMENT(url, true) + +LET expected = [ + {"details":'
MEDUZA
Piece Of Your Heart (feat. Goodboys)'}, + {"details":'
Metanoia Music
Che Crozz x Orbis - Lift Me Up'} +] + +LET html = ( + FOR t IN expected + RETURN '
  • ' + t.details + '
  • ' +) + +INNER_HTML_SET(doc, '.track-list', CONCAT_SEPARATOR('\n', html)) + +LET list = ELEMENT(doc, '.track-list') + +LET actual = ( + FOR item IN ELEMENTS(doc, '.track-list li') + RETURN { + details: INNER_HTML(item, '.track-details'), + } +) + +RETURN EXPECT(expected, actual) \ No newline at end of file diff --git a/e2e/tests/dynamic/element/inner_text/get_by_selector.fql b/e2e/tests/dynamic/element/inner_text/get_by_selector.fql index 67125e87..1a8c65d3 100644 --- a/e2e/tests/dynamic/element/inner_text/get_by_selector.fql +++ b/e2e/tests/dynamic/element/inner_text/get_by_selector.fql @@ -1,11 +1,34 @@ -LET url = @dynamic +LET url = @dynamic + "/#/lists" LET doc = DOCUMENT(url, true) -LET el = ELEMENT(doc, ".jumbotron") -LET expected = `Welcome to Ferret E2E test page!` -LET actual = INNER_TEXT(el, "h1") +LET expected = [ + {"artist":"Lil Tecca","track":"Ransom"}, + {"artist":"NLE Choppa","track":"Shotta Flow (Feat. Blueface) [Remix]"}, + {"artist":"Baby Jesus (DaBaby)","track":"Suge"}, + {"artist":"NLE Choppa","track":"Shotta Flow 3"}, + {"artist":"Lil Tecca","track":"Lil Tecca - Did It Again"}, + {"artist":"NLE Choppa","track":"Shotta Flow"}, + {"artist":"Ynw Melly","track":"Dangerously In Love (772 Love Pt. 2)"}, + {"artist":"POLO G","track":"Polo G feat. Lil TJay - Pop Out"}, + {"artist":"MUSTARD","track":"Ballin' (feat. Roddy Ricch)"}, + {"artist":"Lil Nas X","track":"Panini"}, + {"artist":"Juice WRLD","track":"Juice Wrld - RUN"}, + {"artist":"Shordie Shordie","track":"Betchua (Bitchuary)"}, + {"artist":"Post Malone","track":"Goodbyes (feat. Young Thug)"}, + {"artist":"LIL UZI VERT","track":"Sanguine Paradise"}, + {"artist":"Calboy","track":"Envy Me"}, + {"artist":"Ambjaay","track":"Uno"}, + {"artist":"Lil Tecca","track":"Lil Tecca - Bossanova"}, + {"artist":"Lil Baby","track":"Baby"}, + {"artist":"Lil Tjay","track":"Lil Tjay - Brothers (Prod by JDONTHATRACK & Protegebeatz)"}, + {"artist":"YK Osiris","track":"Worth It"} +] +LET actual = ( + FOR item IN ELEMENTS(doc, '.track-list li') + RETURN { + artist: TRIM(INNER_TEXT(item, '.track-artist')), + track: TRIM(INNER_TEXT(item, '.track-name')) + } +) -LET r1 = '(\n|\s)' -LET r2 = '(\n|\s)' - -RETURN EXPECT(REGEXP_REPLACE(expected, r1, ''), REGEXP_REPLACE(TRIM(actual), r2, '')) \ No newline at end of file +RETURN EXPECT(expected, actual) \ No newline at end of file diff --git a/e2e/tests/dynamic/element/inner_text/set_by_selector.fql b/e2e/tests/dynamic/element/inner_text/set_by_selector.fql new file mode 100644 index 00000000..d956a4f6 --- /dev/null +++ b/e2e/tests/dynamic/element/inner_text/set_by_selector.fql @@ -0,0 +1,37 @@ +LET url = @dynamic + "/#/lists" +LET doc = DOCUMENT(url, true) + +LET expected = [ + { + "artist":'MEDUZA', + "track": 'Piece Of Your Heart (feat. Goodboys)' + }, + { + "artist": 'Metanoia Music', + "track": 'Che Crozz x Orbis - Lift Me Up' + } +] + +LET f = ( + FOR item, idx IN ELEMENTS(doc, '.track-list li') + LIMIT 2 + LET value = expected[idx] + + INNER_HTML_SET(item, '.track-artist', value.artist) + INNER_HTML_SET(item, '.track-name', value.track) + + RETURN NONE +) + +LET list = ELEMENT(doc, '.track-list') + +LET actual = ( + FOR item IN ELEMENTS(doc, '.track-list li') + LIMIT 2 + RETURN { + artist: TRIM(INNER_TEXT(item, '.track-artist')), + track: TRIM(INNER_TEXT(item, '.track-name')) + } +) + +RETURN EXPECT(expected, actual) \ No newline at end of file diff --git a/examples/dynamic-page.fql b/examples/dynamic-page.fql index c837ea96..cd25ac09 100644 --- a/examples/dynamic-page.fql +++ b/examples/dynamic-page.fql @@ -6,6 +6,6 @@ LET tracks = ELEMENTS(doc, '.chartTrack__details') FOR track IN tracks RETURN { - artist: TRIM(INNER_TEXT(track, '.chartTrack__username')), - track: TRIM(INNER_TEXT(track, '.chartTrack__title')) + artist: TRIM(INNER_TEXT(track, '.chartTrack__username')), + track: TRIM(INNER_TEXT(track, '.chartTrack__title')) } diff --git a/pkg/drivers/cdp/element.go b/pkg/drivers/cdp/element.go index 680d3021..98c9aea5 100644 --- a/pkg/drivers/cdp/element.go +++ b/pkg/drivers/cdp/element.go @@ -727,7 +727,22 @@ func (el *HTMLElement) GetInnerTextBySelector(ctx context.Context, selector valu return values.EmptyString, drivers.ErrDetached } - out, err := el.exec.EvalWithReturnValue(ctx, templates.GetInnerTextBySelector(selector.String())) + sel, err := selector.MarshalJSON() + + if err != nil { + return values.EmptyString, err + } + + out, err := el.exec.EvalWithArgumentsAndReturnValue( + ctx, + templates.GetInnerTextBySelector(), + runtime.CallArgument{ + ObjectID: &el.id.objectID, + }, + runtime.CallArgument{ + Value: sel, + }, + ) if err != nil { return values.EmptyString, err @@ -741,7 +756,31 @@ func (el *HTMLElement) SetInnerTextBySelector(ctx context.Context, selector, inn return drivers.ErrDetached } - return el.exec.Eval(ctx, templates.SetInnerTextBySelector(selector.String(), innerText.String())) + sel, err := selector.MarshalJSON() + + if err != nil { + return err + } + + val, err := innerText.MarshalJSON() + + if err != nil { + return err + } + + return el.exec.EvalWithArguments( + ctx, + templates.SetInnerTextBySelector(), + runtime.CallArgument{ + ObjectID: &el.id.objectID, + }, + runtime.CallArgument{ + Value: sel, + }, + runtime.CallArgument{ + Value: val, + }, + ) } func (el *HTMLElement) GetInnerTextBySelectorAll(ctx context.Context, selector values.String) (*values.Array, error) { @@ -749,7 +788,22 @@ func (el *HTMLElement) GetInnerTextBySelectorAll(ctx context.Context, selector v return values.NewArray(0), drivers.ErrDetached } - out, err := el.exec.EvalWithReturnValue(ctx, templates.GetInnerTextBySelectorAll(selector.String())) + sel, err := selector.MarshalJSON() + + if err != nil { + return nil, err + } + + out, err := el.exec.EvalWithArgumentsAndReturnValue( + ctx, + templates.GetInnerTextBySelectorAll(), + runtime.CallArgument{ + ObjectID: &el.id.objectID, + }, + runtime.CallArgument{ + Value: sel, + }, + ) if err != nil { return values.NewArray(0), err @@ -793,7 +847,22 @@ func (el *HTMLElement) GetInnerHTMLBySelector(ctx context.Context, selector valu return values.EmptyString, drivers.ErrDetached } - out, err := el.exec.EvalWithReturnValue(ctx, templates.GetInnerHTMLBySelector(selector.String())) + sel, err := selector.MarshalJSON() + + if err != nil { + return values.EmptyString, err + } + + out, err := el.exec.EvalWithArgumentsAndReturnValue( + ctx, + templates.GetInnerHTMLBySelector(), + runtime.CallArgument{ + ObjectID: &el.id.objectID, + }, + runtime.CallArgument{ + Value: sel, + }, + ) if err != nil { return values.EmptyString, err @@ -807,7 +876,31 @@ func (el *HTMLElement) SetInnerHTMLBySelector(ctx context.Context, selector, inn return drivers.ErrDetached } - return el.exec.Eval(ctx, templates.SetInnerHTMLBySelector(selector.String(), innerHTML.String())) + sel, err := selector.MarshalJSON() + + if err != nil { + return err + } + + val, err := innerHTML.MarshalJSON() + + if err != nil { + return err + } + + return el.exec.EvalWithArguments( + ctx, + templates.SetInnerHTMLBySelector(), + runtime.CallArgument{ + ObjectID: &el.id.objectID, + }, + runtime.CallArgument{ + Value: sel, + }, + runtime.CallArgument{ + Value: val, + }, + ) } func (el *HTMLElement) GetInnerHTMLBySelectorAll(ctx context.Context, selector values.String) (*values.Array, error) { @@ -815,7 +908,22 @@ func (el *HTMLElement) GetInnerHTMLBySelectorAll(ctx context.Context, selector v return values.NewArray(0), drivers.ErrDetached } - out, err := el.exec.EvalWithReturnValue(ctx, templates.GetInnerHTMLBySelectorAll(selector.String())) + sel, err := selector.MarshalJSON() + + if err != nil { + return values.NewArray(0), err + } + + out, err := el.exec.EvalWithArgumentsAndReturnValue( + ctx, + templates.GetInnerHTMLBySelectorAll(), + runtime.CallArgument{ + ObjectID: &el.id.objectID, + }, + runtime.CallArgument{ + Value: sel, + }, + ) if err != nil { return values.NewArray(0), err diff --git a/pkg/drivers/cdp/templates/get_inner_html.go b/pkg/drivers/cdp/templates/get_inner_html.go index 7a0d9e1d..93914229 100644 --- a/pkg/drivers/cdp/templates/get_inner_html.go +++ b/pkg/drivers/cdp/templates/get_inner_html.go @@ -5,28 +5,36 @@ import ( "github.com/MontFerret/ferret/pkg/drivers" ) -func GetInnerHTMLBySelector(selector string) string { - return fmt.Sprintf(` - const selector = "%s"; - const found = document.querySelector(selector); - - if (found == null) { - throw new Error('%s'); +var getInnerHTMLBySelectorTemplate = fmt.Sprintf(` + (el, selector) => { + const found = el.querySelector(selector); + + if (found == null) { + throw new Error('%s'); + } + + return found.innerHTML; } + `, drivers.ErrNotFound, +) - return found.innerHTML; - `, selector, drivers.ErrNotFound) +func GetInnerHTMLBySelector() string { + return getInnerHTMLBySelectorTemplate } -func GetInnerHTMLBySelectorAll(selector string) string { - return fmt.Sprintf(` - const selector = "%s"; - const found = document.querySelectorAll(selector); - - if (found == null) { - throw new Error('%s'); +var getInnerHTMLBySelectorAllTemplate = fmt.Sprintf(` + (el, selector) => { + const found = el.querySelectorAll(selector); + + if (found == null) { + throw new Error('%s'); + } + + return Array.from(found).map(i => i.innerHTML); } + `, drivers.ErrNotFound, +) - return Array.from(found).map(i => i.innerHTML); - `, selector, drivers.ErrNotFound) +func GetInnerHTMLBySelectorAll() string { + return getInnerHTMLBySelectorAllTemplate } diff --git a/pkg/drivers/cdp/templates/get_inner_text.go b/pkg/drivers/cdp/templates/get_inner_text.go index fe806c62..19b739ed 100644 --- a/pkg/drivers/cdp/templates/get_inner_text.go +++ b/pkg/drivers/cdp/templates/get_inner_text.go @@ -5,28 +5,36 @@ import ( "github.com/MontFerret/ferret/pkg/drivers" ) -func GetInnerTextBySelector(selector string) string { - return fmt.Sprintf(` - const selector = "%s"; - const found = document.querySelector(selector); +var getInnerTextBySelectorTemplate = fmt.Sprintf(` + (el, selector) => { + const found = el.querySelector(selector); if (found == null) { - throw new Error('%s'); + throw new Error("%s"); } return found.innerText; - `, selector, drivers.ErrNotFound) + } + `, drivers.ErrNotFound, +) + +func GetInnerTextBySelector() string { + return getInnerTextBySelectorTemplate } -func GetInnerTextBySelectorAll(selector string) string { - return fmt.Sprintf(` - const selector = "%s"; - const found = document.querySelectorAll(selector); +var getInnerTextBySelectorAllTemplate = fmt.Sprintf(` + (el, selector) => { + const found = el.querySelectorAll(selector); if (found == null) { - throw new Error('%s'); + throw new Error("%s"); } return Array.from(found).map(i => i.innerText); - `, selector, drivers.ErrNotFound) + } + `, drivers.ErrNotFound, +) + +func GetInnerTextBySelectorAll() string { + return getInnerTextBySelectorAllTemplate } diff --git a/pkg/drivers/cdp/templates/set_inner_html.go b/pkg/drivers/cdp/templates/set_inner_html.go index 6cdd5675..eb2b2995 100644 --- a/pkg/drivers/cdp/templates/set_inner_html.go +++ b/pkg/drivers/cdp/templates/set_inner_html.go @@ -15,19 +15,20 @@ func SetInnerHTML() string { return setInnerHTMLTemplate } -func SetInnerHTMLBySelector(selector, innerHTML string) string { - return fmt.Sprintf(` - const selector = "%s"; - const found = document.querySelector(selector) - - if (found == null) { - throw new Error('%s'); +var setInnerHTMLBySelectorTemplate = fmt.Sprintf(` + (el, selector, value) => { + const found = el.querySelector(selector); + + if (found == null) { + throw new Error('%s'); + } + + found.innerHTML = value; } - - found.innerHTML = "%s" `, - selector, - drivers.ErrNotFound, - innerHTML, - ) + drivers.ErrNotFound, +) + +func SetInnerHTMLBySelector() string { + return setInnerHTMLBySelectorTemplate } diff --git a/pkg/drivers/cdp/templates/set_inner_text.go b/pkg/drivers/cdp/templates/set_inner_text.go index 94a1a91b..5ba0023f 100644 --- a/pkg/drivers/cdp/templates/set_inner_text.go +++ b/pkg/drivers/cdp/templates/set_inner_text.go @@ -15,19 +15,20 @@ func SetInnerText() string { return setInnerTextTemplate } -func SetInnerTextBySelector(selector, innerText string) string { - return fmt.Sprintf(` - const selector = "%s"; - const found = document.querySelector(selector) - - if (found == null) { - throw new Error('%s'); +var setInnerTextBySelectorTemplate = fmt.Sprintf(` + (el, selector, value) => { + const found = el.querySelector(selector); + + if (found == null) { + throw new Error('%s'); + } + + found.innerText = value; } - - found.innerText = "%s" `, - selector, - drivers.ErrNotFound, - innerText, - ) + drivers.ErrNotFound, +) + +func SetInnerTextBySelector() string { + return setInnerTextBySelectorTemplate }