Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Syn updates #254

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
22 changes: 10 additions & 12 deletions browser/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ var clicks = [
}
var selector = this.selector;
FuncUnit.add({
method: function(success, error){
method: async function(success, error){
options = options || {};
syn("_" + name, this.bind[0], options, success);
await syn[name](this.bind[0], options);
},
success: success,
error: "Could not " + name + " '" + this.selector+"'",
Expand Down Expand Up @@ -146,9 +146,8 @@ $.extend(FuncUnit.prototype, {
text = "[ctrl]a[ctrl-up]\b"
}
FuncUnit.add({
method : function(success, error){
syn("_type", this.bind[0], text, success);

method : async function(success, error){
await syn.type(this.bind[0], text);
},
success : success,
error : "Could not type " + text + " into " + this.selector,
Expand Down Expand Up @@ -177,9 +176,8 @@ $.extend(FuncUnit.prototype, {
keys = "[ctrl]a[ctrl-up]\b"
}
FuncUnit.add({
method : function(success, error){
syn("_type", this.bind[0], keys, success);

method : async function(success, error){
await syn.type(this.bind[0], keys);
},
success : success,
error : "Could not send the keys " + keys + " into " + this.selector,
Expand Down Expand Up @@ -266,8 +264,8 @@ $.extend(FuncUnit.prototype, {

var selector = this.selector;
FuncUnit.add({
method: function(success, error){
syn("_drag", this.bind[0], options, success);
method: async function(success, error){
await syn.drag(this.bind[0], options);
},
success: success,
error: "Could not drag " + this.selector,
Expand Down Expand Up @@ -334,8 +332,8 @@ $.extend(FuncUnit.prototype, {

var selector = this.selector;
FuncUnit.add({
method: function(success, error){
syn("_move", this.bind[0], options, success);
method: async function(success, error){
await syn.move(this.bind[0], options);
},
success: success,
error: "Could not move " + this.selector,
Expand Down
81 changes: 81 additions & 0 deletions new-src/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
const syn = require("syn");

const funcUnitActions = {
click(){
return simpleAsyncAction(this, syn.click);
},

rightClick() {
return simpleAsyncAction(this, syn.rightClick);
},

dblClick() {
return simpleAsyncAction(this, syn.dblclick);
},

scroll(direction, amount) {
let func;

if (direction === 'left' || direction === 'right') {
func = function (el) {
el.scrollLeft = amount;
return el;
}
}

if (direction === 'top' || direction === 'bottom') {
func = function (el) {
el.scrollTop = amount;
return el;
}
}

return simpleSyncAction(this, func);
},

drag() {
return simpleAsyncActionWithArgs(this, syn.drag, arguments);
},

move() {
return simpleAsyncActionWithArgs(this, syn.move, arguments);
},

type(text) {
this.click();
return simpleAsyncActionWithArgs(this, syn.type, arguments);
},

sendKeys(text) {
return simpleAsyncActionWithArgs(this, syn.type, arguments);
}
};


// Helper functions

function simpleAsyncActionWithArgs(elementPromise, action, args) {
return new elementPromise.constructor(function simpleActionWithArgs(resolve, reject) {
elementPromise.then(function (element) {
action(element, ...args).then(() => resolve(element), reject);
}, reject);
});
}

function simpleAsyncAction(elementPromise, action) {
return new elementPromise.constructor(function simpleAction(resolve, reject) {
elementPromise.then(function (element){
action(element).then(()=> resolve(element), reject);
}, reject);
});
}

function simpleSyncAction(elementPromise, action) {
return new elementPromise.constructor(function simpleAction(resolve, reject) {
elementPromise.then(function (element){
resolve( action(element) );
}, reject);
});
}

module.exports = funcUnitActions;
151 changes: 151 additions & 0 deletions new-src/core.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
const Sizzle = require("sizzle");

const {
resolveWhenTrue,
makeExecutorToResolveWhenTrue
} = require('./helpers');

const funcUnitActions = require('./actions');
const funcUnitGetters = require('./getters');
const funcUnitTraversers = require('./traversers');

const funcUnitPrototypeMethods = {
...funcUnitActions,
...funcUnitGetters,
...funcUnitTraversers
};

function makeFuncUnit(defaultWindow) {

function FuncUnit(selector, context) {
let executor;
if(typeof selector === "string") {
let win = getWindow(selector, context || FuncUnit.defaultWindow);

executor = makeExecutorToResolveWhenTrue({
tester: function(){
var documentElement = win.document.documentElement;

if(!documentElement) {
return undefined;
}
var results = Sizzle(selector, documentElement);
// contains will return multiple elements nested inside each other, this helps take the right
// one.

return takeFirstDeepestChild(results);
},
rejectReason: () => new Error("Unable to find "+selector)
})
} else if(typeof selector === "function") {
executor = selector;
} else {
throw "arguments not understood";
}
return Reflect.construct(Promise, [executor], FuncUnit);
};

FuncUnit.defaultWindow = defaultWindow;

Object.assign(
FuncUnit,
Object.fromEntries(
Reflect.ownKeys(Promise)
.filter(key => key !== "length" && key !== "name")
.map(key => [key, Promise[key]])
)
);
// Create the prototype, add methods to it
FuncUnit.prototype = Object.create(Promise.prototype);
FuncUnit.prototype.constructor = FuncUnit;

Object.assign(FuncUnit.prototype, funcUnitPrototypeMethods);

Object.assign(FuncUnit, funcUnitStaticMethods);
return FuncUnit;
}

const funcUnitStaticMethods = {
async useWindow(url){
var width = window.innerWidth;
this.defaultWindow = window.open(url, "funcunit", "height=1000,toolbar=yes,status=yes,left="+width/4);

if(this.defaultWindow && this.defaultWindow.___FUNCUNIT_OPENED) {
this.defaultWindow.close();
this.defaultWindow = window.open(url, "funcunit", "height=1000,toolbar=yes,status=yes,left="+width/4);
}
let stealDone = false, ready = false;

setTimeout(() => ready = true, 123);

await resolveWhenTrue({
tester: () => {


// make sure there is a document
if(!this.defaultWindow.document.documentElement) {
return;
}
if( this.defaultWindow.document.readyState !== "complete" ||
this.defaultWindow.location.href === "about:blank" ||
!this.defaultWindow.document.body ) {
return;
}
this.defaultWindow.___FUNCUNIT_OPENED = true;

// wait for steal to fully load
if( this.defaultWindow.steal ) {
this.defaultWindow.steal.done().then(() => {
stealDone = true;
});
} else {
stealDone = true;
}
return stealDone && ready;
}
})
return this;
}
}

function takeFirstDeepestChild(elements){
var cur = elements[0];
var index = 1;
var next;
while(next = elements[index]) {
if(!next) {
return cur;
}
if(! cur.contains(next) ) {
return cur;
} else {
cur = next;
index++;
}
}
return cur;
}

function getWindowFromElement(element){
const doc = element.ownerDocument;
return doc.defaultView || doc.parentWindow;
}

function getWindow(element, context) {

if (element.nodeName) {
return getWindowFromElement(element);
} else {
if (!context) {
return window;
} else if (context.nodeName === "#document") {
return getWindowFromElement(element);
} else if (context.self === context) {
return context;
} else {
throw new Error("can't find window")
}
}
}

module.exports = makeFuncUnit();
Loading