Skip to content
This repository has been archived by the owner on Apr 23, 2024. It is now read-only.

Commit

Permalink
Merge pull request #24 from miherlosev/master
Browse files Browse the repository at this point in the history
move selector validation into client function
  • Loading branch information
AlexanderMoskovkin authored Sep 20, 2017
2 parents 0e48845 + 4fcce29 commit 7dfe145
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 107 deletions.
9 changes: 7 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"presets": ["es2015"]
}
"presets": [
["es2015", { "loose": true }]
],
"plugins": [
"transform-runtime"
]
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "testcafe-vue-selectors",
"version": "1.0.3",
"version": "2.0.0",
"description": "VueJS selectors for TestCafe",
"repository": "https://github.com/DevExpress/testcafe-vue-selectors",
"author": {
Expand Down
204 changes: 102 additions & 102 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,139 +1,139 @@
import { Selector } from 'testcafe';

export default (selector) => {
if (selector !== void 0 && typeof selector !== 'string')
throw new Error(`If the selector parameter is passed it should be a string, but it was ${typeof selector}`);
export default Selector(complexSelector => {
function validateSelector (selector) {
if (selector !== void 0 && typeof selector !== 'string')
throw new Error(`If the selector parameter is passed it should be a string, but it was ${typeof selector}`);
}

return Selector(complexSelector => {
function validateVueVersion () {
const SUPPORTED_VUE_VERSION = 2;
const vueVersion = parseInt(window.Vue.version.split('.')[0], 10);
function validateVueVersion () {
const SUPPORTED_VUE_VERSION = 2;
const vueVersion = parseInt(window.Vue.version.split('.')[0], 10);

if (vueVersion < SUPPORTED_VUE_VERSION)
throw new Error('testcafe-vue-selectors supports Vue version 2.x and newer');
}

function findFirstRootInstance () {
let instance = null;
const treeWalker = document.createTreeWalker(document, NodeFilter.SHOW_ELEMENT, () => NodeFilter.FILTER_ACCEPT, false);
let currentNode = treeWalker.nextNode();
if (vueVersion < SUPPORTED_VUE_VERSION)
throw new Error('testcafe-vue-selectors supports Vue version 2.x and newer');
}

while (currentNode) {
instance = currentNode.__vue__;
function findFirstRootInstance () {
let instance = null;
const treeWalker = document.createTreeWalker(document, NodeFilter.SHOW_ELEMENT, () => NodeFilter.FILTER_ACCEPT, false);
let currentNode = treeWalker.nextNode();

if (instance)
break;

currentNode = treeWalker.nextNode();
}
while (currentNode) {
instance = currentNode.__vue__;

return instance;
}

function getComponentTagNames (componentSelector) {
return componentSelector
.split(' ')
.filter(el => !!el)
.map(el => el.trim().toLowerCase());
}
if (instance)
break;

function getComponentTag (instance) {
return instance.$options.name ||
instance.$options._componentTag ||
instance.$options.__file ||
'';
currentNode = treeWalker.nextNode();
}

function filterNodes (root, tags) {
const foundComponents = [];

function walkVueComponentNodes (node, tagIndex, checkFn) {
if (checkFn(node, tagIndex)) {
if (tagIndex === tags.length - 1) {
foundComponents.push(node.$el);
return;
}

tagIndex++;
return instance;
}

function getComponentTagNames (componentSelector) {
return componentSelector
.split(' ')
.filter(el => !!el)
.map(el => el.trim().toLowerCase());
}

function getComponentTag (instance) {
return instance.$options.name ||
instance.$options._componentTag ||
instance.$options.__file ||
'';
}

function filterNodes (root, tags) {
const foundComponents = [];

function walkVueComponentNodes (node, tagIndex, checkFn) {
if (checkFn(node, tagIndex)) {
if (tagIndex === tags.length - 1) {
foundComponents.push(node.$el);
return;
}

for (let i = 0; i < node.$children.length; i++) {
const childNode = node.$children[i];

walkVueComponentNodes(childNode, tagIndex, checkFn);
}
tagIndex++;
}

walkVueComponentNodes(root, 0, (node, tagIndex) => tags[tagIndex] === getComponentTag(node));
for (let i = 0; i < node.$children.length; i++) {
const childNode = node.$children[i];

return foundComponents;
walkVueComponentNodes(childNode, tagIndex, checkFn);
}
}

if (!window.Vue)
return document.querySelectorAll(complexSelector);
walkVueComponentNodes(root, 0, (node, tagIndex) => tags[tagIndex] === getComponentTag(node));

validateVueVersion();
return foundComponents;
}

const rootInstance = findFirstRootInstance();
if (!window.Vue)
return document.querySelectorAll(complexSelector);

if (!rootInstance)
return null;
validateSelector(complexSelector);
validateVueVersion();

if (!complexSelector)
return rootInstance.$el;
const rootInstance = findFirstRootInstance();

const componentTags = getComponentTagNames(complexSelector);
if (!rootInstance)
return null;

return filterNodes(rootInstance, componentTags);
})(selector).addCustomMethods({
getVue: (node, fn) => {
function getData (instance, prop) {
const result = {};
if (!complexSelector)
return rootInstance.$el;

Object.keys(prop).forEach(key => {
result[key] = instance[key];
});
const componentTags = getComponentTagNames(complexSelector);

return filterNodes(rootInstance, componentTags);
}).addCustomMethods({
getVue: (node, fn) => {
function getData (instance, prop) {
const result = {};

return result;
}
Object.keys(prop).forEach(key => {
result[key] = instance[key];
});

function getProps (instance) {
return getData(instance, instance.$options.props || {});
}

function getState (instance) {
const props = instance._props || instance.$options.props;
const getters = instance.$options.vuex && instance.$options.vuex.getters;
const result = {};
return result;
}

Object.keys(instance._data)
.filter(key => !(props && key in props) && !(getters && key in getters))
.forEach(key => {
result[key] = instance._data[key];
});
function getProps (instance) {
return getData(instance, instance.$options.props || {});
}

return result;
}
function getState (instance) {
const props = instance._props || instance.$options.props;
const getters = instance.$options.vuex && instance.$options.vuex.getters;
const result = {};

function getComputed (instance) {
return getData(instance, instance.$options.computed || {});
}
Object.keys(instance._data)
.filter(key => !(props && key in props) && !(getters && key in getters))
.forEach(key => {
result[key] = instance._data[key];
});

return result;
}

const nodeVue = node.__vue__;
function getComputed (instance) {
return getData(instance, instance.$options.computed || {});
}

if (!nodeVue)
return null;
const nodeVue = node.__vue__;

const props = getProps(nodeVue);
const state = getState(nodeVue);
const computed = getComputed(nodeVue);
if (!nodeVue)
return null;

if (typeof fn === 'function')
return fn({ props, state, computed });
const props = getProps(nodeVue);
const state = getState(nodeVue);
const computed = getComputed(nodeVue);

return { props, state, computed };
}
});
};
if (typeof fn === 'function')
return fn({ props, state, computed });

return { props, state, computed };
}
});
5 changes: 3 additions & 2 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ test('composite selector', async t => {
test('should throw exception for non-valid selectors', async t => {
for (const selector of [null, false, {}, 42]) {
try {
VueSelector(selector);
await VueSelector(selector);
await t.expect(false).ok('The selector should throw an error but it doesn\'t.');
}
catch (e) {
await t.expect(e.message).eql(`If the selector parameter is passed it should be a string, but it was ${typeof selector}`);
await t.expect(e.errMsg).contains(`If the selector parameter is passed it should be a string, but it was ${typeof selector}`);
}
}
});
Expand Down

0 comments on commit 7dfe145

Please sign in to comment.