Skip to content

Commit

Permalink
Added history cue structure
Browse files Browse the repository at this point in the history
  • Loading branch information
Szabo Bogdan committed Sep 18, 2016
1 parent 8d7c148 commit e993cd8
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 32 deletions.
1 change: 1 addition & 0 deletions source/session.d
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module selenium.session;

import selenium.api;
import std.stdio;
import vibe.data.json;

immutable class SeleniumSession
{
Expand Down
188 changes: 156 additions & 32 deletions source/workflow.d
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ import std.exception;
import std.traits;
import std.meta;
import std.algorithm.searching;
import std.algorithm.iteration;
import std.range;

import selenium.session;
import selenium.api;


import std.string;
import std.conv;

Expand All @@ -29,7 +33,6 @@ class SeleniumPage {
}
}


class WorkflowCheck(T, U) : Workflow!(T, U) {

this(T child, U cls) {
Expand Down Expand Up @@ -91,12 +94,7 @@ class Workflow(T, U) {
}
}

auto goTo(string url) {
session.navigation.url = url;
return this;
}

public bool hasStep(string name)() {
bool hasStep(string name)() {
static if(!is(U == void*) && __traits(hasMember, cls, name)) {
return true;
} else static if(!is(T == void*)) {
Expand All @@ -118,9 +116,7 @@ class Workflow(T, U) {
}
}

auto opDispatch(string name, T...)(T props) if(name != "define" && name != "hasStep") {
enforce(hasStep!name, "The step `" ~ name ~ "` is undefined.");

private void logDispatch(string name, T...)(T props) {
string stringParams = "";

static if(T.length == 0) {
Expand All @@ -132,26 +128,50 @@ class Workflow(T, U) {

logInfo("=> " ~ name ~ ":" ~ stringParams);
}
}

static if(!is(U == void*)) {
static if(__traits(hasMember, cls, name)) {
alias expectedParam = Parameters!(__traits(getMember, cls, name));
private auto callClassMember(string name, T...)(T props) {
alias expectedParam = Parameters!(__traits(getMember, cls, name));

static if(expectedParam.length == props.length + 1 && is(expectedParam[0] == typeof(session))) {
alias finalProps = AliasSeq!(session, props);
} else {
alias finalProps = props;
}
enum diffParameters = expectedParam.length - props.length;

static if(is(ReturnType!(__traits(getMember, cls, name)) == void)) {
__traits(getMember, cls, name)(finalProps);
return this;
} else {
return __traits(getMember, cls, name)(finalProps);
}
} else static if(!is(T == void*)) {
return child.opDispatch!name(props);
static assert(diffParameters <= 2, "Can not call `" ~ name ~ "` due invalid number of parameters");

static if(diffParameters) {
assert(is(expectedParam[0] == typeof(session)) || is(expectedParam[0] == typeof(this)),
"First parameter expected of type `immutable SeleniumSession` or `Workflow`");

static if(is(expectedParam[0] == typeof(session))) {
alias prepend = AliasSeq!(session);
} else {
alias prepend = AliasSeq!(this);
}
} else {
alias prepend = AliasSeq!();
}

alias finalProps = AliasSeq!(prepend, props);

static if(is(ReturnType!(__traits(getMember, cls, name)) == void)) {
__traits(getMember, cls, name)(finalProps);
return this;
} else {
return __traits(getMember, cls, name)(finalProps);
}
}

auto opDispatch(string name, T...)(T props) if(name != "define" && name != "hasStep") {
enforce(hasStep!name, "The step `" ~ name ~ "` is undefined.");
logDispatch!name(props);

static assert(!is(U == void*) && !is(T == void*), "Can not call method `" ~ name ~ "` on `void` child and class.");

enum classHasMember = __traits(hasMember, cls, name);

static if(classHasMember) {
return callClassMember!name(props);
} else static if(!is(T == void*)) {
return child.opDispatch!name(props);
}
}
}
Expand All @@ -168,6 +188,62 @@ auto define(T, U)(T workflow, U obj) {
return new Workflow!(T, U)(workflow, obj);
}

class WebNavigation {
void goTo(immutable SeleniumSession session, string url) {
session.navigation.url = url;
}
}

struct HistoryCue(T) {
alias E = ReturnType!T;

private {
immutable SeleniumSession session;
T callback;
E result;

ulong index = 0;

string expectedUrl;
}

this(immutable SeleniumSession session, T callback) {
this.session = session;
this.callback = callback;

this.expectedUrl = session.navigation.url;
this.result = callback(session, index);
}

E front() {
return result;
}

E moveFront() {
return result;
}

void popFront() {
index++;

while(this.expectedUrl != session.navigation.url) {
session.navigation.back;
}

writeln("pop front ", session.navigation.url);

result = callback(session, index);
}

bool empty() {
return result is null;
}
}

auto historyCue(T)(immutable SeleniumSession session, T callback) {
return HistoryCue!T(session, callback);
}

@("some workflow examples")
unittest
{
Expand All @@ -194,6 +270,41 @@ unittest
void selectFirstResult(immutable SeleniumSession session) {
selectResultNumber(session, 0);
}

auto eachResult(immutable SeleniumSession session) {
return session.historyCue(&this.getResult);
}

auto getResult(immutable SeleniumSession session, ulong index) {
auto list = session.findMany("li.s-result-item a.s-access-detail-page".cssLocator);

if(index >= list.length) {
return null;
}

auto element = list[index];
auto position = element.position;

session.currentWindow.execute("window.scrollTo(" ~ position.x.to!string ~ "," ~ position.y.to!string ~ ")");
element.click;

class ResultPage {
private immutable SeleniumSession session;

this(immutable SeleniumSession session) {
this.session = session;

writeln("Result Page " , session.navigation.url);
}

string getTitle() {
writeln("get title ", session.findOne("productTitle".idLocator).text);
return session.findOne("productTitle".idLocator).text;
}
}

return new ResultPage(session);
}
}

class ProductPage : SeleniumPage {
Expand All @@ -208,17 +319,30 @@ unittest

SeleniumPage productPage = new ProductPage(session);

auto workflow = define(session).define!"productPage"(productPage).define(new Steps);

auto workflow = define(session)
.define!"productPage"(productPage)
.define(new Steps)
.define(new WebNavigation);
/*
workflow
.goTo("https://www.amazon.com")
.opDispatch!"goTo"("https://www.amazon.com")
.opDispatch!"search"("Maggy London Womens")
.selectResultNumber(2)
.opDispatch!"productPage".check.isPresent;
.productPage
.check
.isPresent;
auto chk = workflow
workflow
.goTo("https://www.amazon.com")
.search("Maggy London Womens")
.selectFirstResult
.check.productPage.isPresent;
.check
.productPage.isPresent;*/

workflow
.goTo("https://www.amazon.com")
.search("Maggy London Womens")
.eachResult
.map!(a => a.getTitle.canFind("Maggy London Women's"))
.reduce!((a, b) => a && b);
}

0 comments on commit e993cd8

Please sign in to comment.