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 #32 from LavrovArtem/i21
Browse files Browse the repository at this point in the history
Support components loaded via vue-loader (close #21)
  • Loading branch information
miherlosev authored Nov 20, 2017
2 parents bb07a6d + a179c37 commit cb84226
Show file tree
Hide file tree
Showing 12 changed files with 196 additions and 37 deletions.
20 changes: 13 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "testcafe-vue-selectors",
"version": "2.0.0",
"version": "2.1.0",
"description": "VueJS selectors for TestCafe",
"repository": "https://github.com/DevExpress/testcafe-vue-selectors",
"author": {
Expand All @@ -14,8 +14,8 @@
"license": "MIT",
"scripts": {
"lint": "eslint src/index.js test/index.js",
"http-server": "http-server ./ -s",
"testcafe": "testcafe all test/index.js --app \"npm run http-server\" --app-init-delay 3000",
"test-server": "webpack-dev-server",
"testcafe": "testcafe all test/*.js --app \"npm run test-server\" --app-init-delay 3000",
"test": "npm run lint && npm run build && npm run testcafe",
"build": "babel src --out-dir lib",
"publish-please": "publish-please",
Expand All @@ -24,13 +24,19 @@
"devDependencies": {
"babel-cli": "^6.22.2",
"babel-eslint": "^7.1.1",
"babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.22.0",
"css-loader": "^0.28.7",
"eslint": "^3.15.0",
"eslint-plugin-testcafe": "^0.2.1",
"http-server": "^0.9.0",
"publish-please": "^2.2.0",
"vue": "^2.1.10",
"testcafe": "*"
"pug": "^2.0.0-rc.4",
"testcafe": "*",
"vue": "^2.5.4",
"vue-loader": "^13.5.0",
"vue-template-compiler": "^2.5.4",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.1"
},
"keywords": [
"testcafe",
Expand All @@ -40,6 +46,6 @@
"plugin"
],
"peerDependencies": {
"testcafe": "*"
"testcafe": "*"
}
}
45 changes: 28 additions & 17 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,39 @@ export default Selector(complexSelector => {
throw new Error(`If the selector parameter is passed it should be a string, but it was ${typeof selector}`);
}

function validateVueVersion () {
const SUPPORTED_VUE_VERSION = 2;
const vueVersion = parseInt(window.Vue.version.split('.')[0], 10);
function validateVueVersion (rootInstance) {
const MAJOR_SUPPORTED_VUE_VERSION = 2;
const vueVersion = parseInt(findVueConstructor(rootInstance).version.split('.')[0], 10);

if (vueVersion < SUPPORTED_VUE_VERSION)
if (vueVersion < MAJOR_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();
/*eslint-disable no-unused-vars, no-eval*/
function findVueConstructor (rootInstance) {
// NOTE: Testcafe does not support a ClientFunction containing polyfilled functions. See list in
// https://github.com/babel/babel/blob/master/packages/babel-plugin-transform-runtime/src/definitions.js.
// This is why, we use this hack.
let Vue = eval('Object.getPrototypeOf(rootInstance)').constructor;

while (currentNode) {
instance = currentNode.__vue__;
while (Vue.super)
Vue = Vue.super;

if (instance)
break;
return Vue;
}
/*eslint-enable no-unused-vars, no-eval*/

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

while (!instance && treeWalker.nextNode())
instance = treeWalker.currentNode.__vue__;

return instance;
}
Expand Down Expand Up @@ -70,17 +82,16 @@ export default Selector(complexSelector => {
return foundComponents;
}

if (!window.Vue)
return document.querySelectorAll(complexSelector);

validateSelector(complexSelector);
validateVueVersion();

const rootInstance = findFirstRootInstance();

if (!rootInstance)
return null;

validateVueVersion(rootInstance);

if (!complexSelector)
return rootInstance.$el;

Expand Down
File renamed without changes.
16 changes: 16 additions & 0 deletions test/data/vue-loader/components/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template lang="pug">
#app
h1 Header
list#list1
list#list2
</template>
<script>
import List from './list.vue';
export default {
components: { List },
name: 'app'
};
</script>
<style>
</style>
15 changes: 15 additions & 0 deletions test/data/vue-loader/components/list-item.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template lang="pug">
li(:id='id')
p {{ id }}
</template>
<script>
export default {
name: 'list-item',
props: ['id']
};
</script>
<style>
li {
margin: 0 20px;
}
</style>
37 changes: 37 additions & 0 deletions test/data/vue-loader/components/list.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<template lang="pug">
.list-wrapper
h4 {{ id }}
ul(:id='id')
each index in [1, 2, 3]
list-item(:id=`getId(${index})`)
</template>
<script>
import ListItem from './list-item.vue';
export default {
components: { ListItem },
name: 'list',
props: ['id'],
computed: {
reversedId: function () {
return this.id.split('').reverse().join('');
}
},
methods: {
getId: function (postfix) {
return this.id + '-item' + postfix;
}
}
};
</script>
<style>
.list-wrapper {
border-left: dashed 4px #8BC34A;
width: 400px;
}
h4 {
border-bottom: solid 3px beige;
margin: 0 20px;
}
</style>
14 changes: 14 additions & 0 deletions test/data/vue-loader/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>vue-loader</title>
</head>
<body>
<div id="app">
<list id="list1"></list>
<list id="list2"></list>
</div>
<script src="/build.js"></script>
</body>
</html>
12 changes: 12 additions & 0 deletions test/data/vue-loader/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Vue from 'vue';
import App from './components/app.vue';

new Vue({
el: '#app',
render: h => h(App),
data () {
return {
rootProp1: 1
};
}
});
21 changes: 8 additions & 13 deletions test/index.js → test/vue-js.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import VueSelector from '../lib';
import { ClientFunction } from 'testcafe';

fixture `VueSelector`
.page('http://localhost:8080/test/data');
fixture `vue-js`
.page `http://localhost:8080/test/data/vue-js/`;

test('root node', async t => {
const root = VueSelector();
const rootVue = await root.getVue();

await t.expect(root.exists).ok()
await t
.expect(root.exists).ok()
.expect(rootVue.state.rootProp1).eql(1);
});

test('selector', async t => {
const list = VueSelector('list');
const listVue = await list.getVue();

await t.expect(list.count).eql(2)
await t
.expect(list.count).eql(2)
.expect(VueSelector('list-item').count).eql(6)
.expect(listVue.props.id).eql('list1')
.expect(listVue.computed.reversedId).eql('1tsil');
Expand All @@ -27,7 +29,8 @@ test('composite selector', async t => {
const listItemVue6 = await listItem.nth(5).getVue();
const listItemVue5Id = listItem.nth(4).getVue(({ props }) => props.id);

await t.expect(listItem.count).eql(6)
await t
.expect(listItem.count).eql(6)
.expect(listItemVue6.props.id).eql('list2-item3')
.expect(listItemVue5Id).eql('list2-item2');
});
Expand All @@ -44,14 +47,6 @@ test('should throw exception for non-valid selectors', async t => {
}
});

test('there is no Vue on the tested page', async t => {
await ClientFunction(() => window.Vue = null)();

const body = await VueSelector('body');

await t.expect(body.tagName).eql('body');
});

test('supported version', async t => {
await ClientFunction(() => window.Vue.version = '1.0.28')();

Expand Down
15 changes: 15 additions & 0 deletions test/vue-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import VueSelector from '../lib';

fixture `vue-loader`
.page `http://localhost:8080/test/data/vue-loader/`;

test('composite selector', async t => {
const listItem = VueSelector('list list-item');
const listItemVue6 = await listItem.nth(5).getVue();
const listItemVue5Id = listItem.nth(4).getVue(({ props }) => props.id);

await t
.expect(listItem.count).eql(6)
.expect(listItemVue6.props.id).eql('list2-item3')
.expect(listItemVue5Id).eql('list2-item2');
});
9 changes: 9 additions & 0 deletions test/without-vue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import VueSelector from '../lib';

fixture `page without vue`;

test('there is no Vue on the tested page', async t => {
const listVueSelector = VueSelector('list');

await t.expect(listVueSelector.count).eql(0);
});
29 changes: 29 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
var path = require('path');

module.exports = {
entry: path.resolve(__dirname, './test/data/vue-loader/main.js'),

output: {
path: path.resolve(__dirname, 'dist'),
filename: 'build.js'
},

module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
},

devServer: {
noInfo: true,
port: 8080
}
};

0 comments on commit cb84226

Please sign in to comment.