GithubHelp home page GithubHelp logo

devexpress / testcafe-vue-selectors Goto Github PK

View Code? Open in Web Editor NEW
103.0 22.0 19.0 182 KB

TestCafe selector extensions for Vue.js apps.

Home Page: https://testcafe.io

License: MIT License

JavaScript 76.39% HTML 10.77% Vue 12.84%
testcafe vue vuejs selectors plugin

testcafe-vue-selectors's Introduction

DEPREDCATED

The TestCafe team no longer maintains the testcafe-vue-selectors repository. If you want to take over the project, we'll be happy to hand it over. To contact the team, create a new GitHub issue.

testcafe-vue-selectors

This plugin provides selector extensions that make it easier to test Vue components with TestCafe. These extensions allow you to test Vue component state and result markup together.

Install

$ npm install testcafe-vue-selectors

Usage

Create selectors for Vue components

VueSelector allows you to select page elements by the component tagName or the nested component tagNames.

Suppose you have the following markup.

<div id="todo-app">
    <todo-input ref="ref-todo-input-1"/>
    <todo-list ref="ref-todo-list-1">
        <todo-item ref="ref-todo-item-1" priority="High">Item 1</todo-item>
        <todo-item ref="ref-todo-item-2" priority="Low">Item 2</todo-item>
    </todo-list>   
    <div className="items-count">Items count: <span>{{itemCount}}</span></div>
</div>
<script>
    Vue.component('todo-input', {...});
    Vue.component('todo-list', {...});
    Vue.component('todo-item', {...});
    
    new Vue({ 
        el:   '#todo-app',
        data: {...}
    });
</script>

To get the root Vue node, use the VueSelector constructor without parameters.

import VueSelector from 'testcafe-vue-selectors';

const rootVue = VueSelector();

The rootVue variable will contain the <div id="todo-app"> element.

To get a root DOM element for a component, pass the component name to the VueSelector constructor.

import VueSelector from 'testcafe-vue-selectors';

const todoInput = VueSelector('todo-input');

To obtain a component based on its reference ID, pass the ref attribute value prepended with ref: to the VueSelector constructor.

import VueSelector from 'testcafe-vue-selectors';

const todoInput = VueSelector('ref:ref-todo-item-1');

To obtain a nested component, you can use a combined selector.

import VueSelector from 'testcafe-vue-selectors';

const todoItem       = VueSelector('todo-list todo-item');
const todoList1Items = VueSelector('ref:todo-list-1 todo-item');
const todoItem1      = VueSelector('todo-list ref:ref-todo-item-1');
const todoList1Item1 = VueSelector('ref:ref-todo-list-1 ref:ref-todo-item-1');

You can combine Vue selectors with testcafe Selector filter functions like .find, .withText, .nth and other.

import VueSelector from 'testcafe-vue-selectors';

var itemsCount = VueSelector().find('.items-count span');

Let’s use the API described above to add a task to a Todo list and check that the number of items changed.

import VueSelector from 'testcafe-vue-selectors';

fixture `TODO list test`
	.page('http://localhost:1337');

test('Add new task', async t => {
    const todoTextInput = VueSelector('todo-input');
    const todoItem      = VueSelector('todo-list todo-item');

    await t
        .typeText(todoTextInput, 'My Item')
        .pressKey('enter')
        .expect(todoItem.count).eql(3);
});
Obtaining component's props, computed, state and ref

In addition to DOM Node State, you can obtain state, computed, props or ref of a Vue component.

To get these data, use the Vue selector’s .getVue() method.

The getVue() method returns a client function. This function resolves to an object that contains component properties.

const vueComponent      = VueSelector('componentTag');
const vueComponentState = await vueComponent.getVue();

// >> vueComponentState
//
// {
//     props:    <component_props>,
//     state:    <component_state>,
//     computed: <component_computed>,
//     ref:      <component_ref>
// }

The returned client function can be passed to assertions activating the Smart Assertion Query mechanism.

Example

import VueSelector from 'testcafe-vue-selector';

fixture `TODO list test`
	.page('http://localhost:1337');

test('Check list item', async t => {
    const todoItem    = VueSelector('todo-item');
    const todoItemVue = await todoItem.getVue();

    await t
        .expect(todoItemVue.props.priority).eql('High')
        .expect(todoItemVue.state.isActive).eql(false)
        .expect(todoItemVue.computed.text).eql('Item 1');
});

As an alternative, the .getVue() method can take a function that returns the required property, state, computed property or reference ID. This function acts as a filter. Its argument is an object returned by .getVue(), i.e. { props: ..., state: ..., computed: ..., ref: ...}.

VueSelector('component').getVue(({ props, state, computed, ref }) => {...});

Example

import VueSelector from 'testcafe-vue-selectors';

fixture `TODO list test`
    .page('http://localhost:1337');

test('Check list item', async t => {
    const todoItem = VueSelector('todo-item');

    await t
        .expect(todoItem.getVue(({ props }) => props.priority)).eql('High')
        .expect(todoItem.getVue(({ state }) => state.isActive)).eql(false)
        .expect(todoItem.getVue(({ computed }) => computed.text)).eql('Item 1')
        .expect(todoItem.getVue(({ ref }) => ref)).eql('ref-item-1');
});

The .getVue() method can be called for the VueSelector or the snapshot this selector returns.

Limitations

testcafe-vue-selectors support Vue starting with version 2.

Only the property, state, computed property and reference ID parts of a Vue component are available.

To check if a component can be found, use the vue-dev-tools extension for Google Chrome.

Pages with multiple Vue root nodes are not supported.

testcafe-vue-selectors's People

Contributors

aleks-pro avatar alexandermoskovkin avatar alexskorkin avatar andreybelym avatar async0x42 avatar churkin avatar farfurix avatar fjij avatar inikulin avatar kirovboris avatar lavrovartem avatar leonardovilarinho avatar miherlosev avatar thomasleveil avatar vasilystrelyaev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

testcafe-vue-selectors's Issues

How to get to deeply nested component?

How do I get to TaskList component? Do I need to provide all the elements from all the way from Root onto TaskList?

const listItem = VueSelector('Root App Layout QLayout QPageContainer TodoPage QPage TaskList');

Is their a good tutorial / video on a deep tree like that? The problem is I am using Quasar and so I don't have complete control on how deep the tree gets.

image

It would be great if I could get to TaskList simply by specifying:

const listItem = VueSelector('TaskList');

"babel-core" should be included in package

I got an error when using testcafe-vue-selectors with testcafe 1.14.0 as follows:

 Running tests in:
 - Chrome 89.0.4389.128 / macOS 11.2.3

...

ERROR Cannot prepare tests due to an error.

Error: Cannot find module 'babel-runtime/core-js/object/keys'
Require stack:
- /.../frontend/node_modules/testcafe-vue-selectors/lib/index.js
- /.../frontend/tests/login.js
- /.../frontend/node_modules/testcafe/lib/compiler/test-file/formats/es-next/compiler.js
- /.../frontend/node_modules/testcafe/lib/compiler/compilers.js
- /.../frontend/node_modules/testcafe/lib/compiler/index.js
- /.../frontend/node_modules/testcafe/lib/runner/bootstrapper.js
- /.../frontend/node_modules/testcafe/lib/runner/index.js
- /.../frontend/node_modules/testcafe/lib/testcafe.js
- /.../frontend/node_modules/testcafe/lib/index.js
- /.../frontend/node_modules/testcafe/lib/cli/cli.js
- /.../frontend/node_modules/testcafe/lib/cli/index.js
    at Object.<anonymous> (/.../frontend/node_modules/testcafe-vue-selectors/lib/index.js:5:13)
    at Object.<anonymous> (/.../frontend/tests/login.js:3:1)

This issue has been resolved after I installed babel-core as yarn add --dev babel-core so I think babel-core should be included in this package.

Selector returns wrong DOM node if component doesn't render a real DOM elements

Markup for reproduce:

<html>
    <head>
		<script src="vue.js"></script>
	</head>
	<body>
	    <div id='root'>
			<App></App>
		</div>
		<script>
		   Vue.component('total-value', {  
		       props: ['formatProperty'],
		       template: '<div>{{ formatProperty }}</div>' 
		   });
		   Vue.component('Hello', { template: '<total-value formatProperty="%d"></total-value>' });
		   Vue.component('App', { template: '<Hello></Hello>' });
		   
		   new Vue({ el: '#root' });
		</script>
	</body>
</html>

Test for reproduce:

import VueSelector from "testcafe-vue-selectors";

fixture `https://stackoverflow.com/questions/44585727/testcafe-vue-selectors-cant-grab-vue-component`
    .page('http://localhost:8080');

test('test', async t => {
    const totalValue = VueSelector("total-value");

    await t.expect(totalValue.getVue(({ props }) => props.formatProperty)).eql('%d');
});

Errors on passing to component some variables with specific names like value or data

Test case scenario:
There are two components: A and B. A is parent of B and A is passing to B variable "value" via prop named "message" like this:
<component-b :message="value"></component-b>

Value is defined in data section of component A. When testcafe tests this structure it constantly throws errors to client console:

Property of method "nodeName" (or "nodeType") is not defined on the instance but referenced during render...

When variable is not called like "value" or "data" (these names are not reserved keywords in Vue) then errors are not throwed.

To reproduce these errors, download my spa template (testcafe-error branch):

git clone https://github.com/Ranmus/vue-spa-template.git
cd vue-spa-template
git checkout testcafe-error
yarn
npm run tests:functional

I've added 60 seconds to wait until test is passed. During this time check client console.

Can not select <router-view> component

I'm trying to test certain parts of my applications computed properties such as locale or form validation results which are contained on the component loaded into the <router-view> component

You can see in the screenshot

https://imgur.com/PswNqQi/

my default route view loads up my welcome component, using VueSelector() how do I actually select this component to access the state/prop/ computed data.

If i do

const root = VueSelector()
const rootVue = await root.getVue()

This selects the <QLayout> component

If I do

const welcome = VueSelector('welcome')
const welcomeVue = await welcome.getVue()

I get a

node.vue undefined

I've tried passing all sorts of combinations into VueSelector like

VueSelector('q-layout welcome')
VueSelector('router-view')
VueSelector('q-layout router-view')
VueSelector('router-view welcome')

None of which actually select the component served from the route. I can however select any component nested within welcome such as the Login component like

const login = VueSelector('login')
const loginVue = await login.getVue()

await t
.expect(loginVue.computed.isAuthenticated).eql(false)
.expect(loginVue.props.facebook).eql(true)

Any help is really appreciated because otherwise I can't test alot of data on any components server from the router

Can't install vue-selectors

I have testcafe installed and working but every time I run npm install testcafe-vue-selectors
I get this output.

npm WARN saveError ENOENT: no such file or directory, open '/Users/username/Downloads/package.json'
npm WARN enoent ENOENT: no such file or directory, open '/Users/username/Downloads/package.json'
npm WARN Downloads No description
npm WARN Downloads No repository field.
npm WARN Downloads No README data
npm WARN Downloads No license field.

+ [email protected]
updated 1 package in 3.792s

How to get the text of the component q-toolbar-title?

Hi all

I have built a webapp with https://quasar.dev/ that looks as the following:
Screenshot from 2020-10-02 20-30-38

It is a very simple page with the toolbar component.
I have tried to write a test that should validate, if the component q-toolbar-title contains text Databaker.

The created test:

import {ClientFunction} from 'testcafe';
import VueSelector from 'testcafe-vue-selectors';

fixture`Getting Started`
    .page`http://127.0.0.1:3000/`;

const getLocation = ClientFunction(() => document.location.href);

test(`Validate page title`, async t => {

    const toolbarTitle = VueSelector(`q-toolbar-title`);
    const textTitle = await toolbarTitle.getVue();

    await t
        .expect(getLocation()).contains(`oic.dev.example.io`)
        .typeText(`#username`, `[email protected]`)
        .typeText(`#password`, `password`)
        .click(`#kc-login`)
        .wait(3000)
        .expect(textTitle.computed.text)
        .eql(`Databaker`);

});

the part

        .expect(getLocation()).contains(`oic.dev.example.io`)
        .typeText(`#username`, `[email protected]`)
        .typeText(`#password`, `password`)
        .click(`#kc-login`)

works as expect but the test failed because of

 ✖ Validate page title

   1) An error occurred in getVue code:
      
      TypeError: Cannot read property '__vue__' of undefined

      Browser: Chrome 85.0.4183.121 / Linux 0.0

          7 |const getLocation = ClientFunction(() => document.location.href);
          8 |
          9 |test(`Validate page title`, async t => {
         10 |
         11 |    const toolbarTitle = VueSelector(`q-toolbar-title`);
       > 12 |    const textTitle = await toolbarTitle.getVue();
         13 |
         14 |    console.log(toolbarTitle.withText);
         15 |
         16 |    await t
         17 |        .expect(getLocation()).contains(`oic.dev.databaker.io`)

The Vue template:

<template>
  <q-layout view="lHh Lpr lFf">
    <q-header elevated>
      <q-toolbar>
        <q-toolbar-title>
          Databaker
        </q-toolbar-title>
      </q-toolbar>
    </q-header>

    <q-page-container>
      <router-view/>
    </q-page-container>
  </q-layout>
</template

How to write the test correctly?

Thanks

.getVue() causes error

Hi,

I want to get component props but get this messy error. I've already followed the instruction. Still don't know where it came from.

image

<script>
// BarChart.vue
import { Bar } from 'vue-chartjs';
export default {
  extends: Bar,
  props: ['chartData'],
  data() {
    return {
      options: {},
    }
  },
  watch: {
    chartData: {
      deep: true,
      handler() {
        this.renderChart(this.chartData, this.options);
      },
    },
  },
  mounted() {
    this.renderChart(this.data, this.options);
  },
};
</script>
// Test file
  const Chart = await VueSelector('BarChart');
  const response = await fetchData(
    COUNTRIES.find((c) => c.name === 'Viet Nam')
  );
  try {
    const chartData = await Chart.getVue(({ props }) => props.chartData);
    await controller.expect(Chart.exists).ok();
    await controller.expect(chartData).eql(response);
  } catch (e) {
    console.error(e);
  }

Error "_keys2 is not defined" when calling .getVue()

I got an issue when I tried to call .getValue() of component in app with Vuetify. I have tried other components but the result was the same.
Can anyone let me know how to get through?

Environments

  • Chrome 89.0.4389.128 / macOS 11.2.3
  • node: v14.15.5
  • yarn: 1.22.10
  • testcafe: 1.14.0
  • testcafe-vue-selectors: 3.1.0
  • vuetify: 2.4.2

Test Codes

const transfersTable = VueSelector('Transfer SingleAccountStatus v-data-table');
await t.hover(transfersTable); // OK

const transfersTableValues = await transfersTable.getVue(); // NOT OK
console.log(transfersTableValues);

image

Results

  1) An error occurred in getVue code:

      ReferenceError: _keys2 is not defined

      Browser: Chrome 89.0.4389.128 / macOS 11.2.3

         20 |    .click(proceedButton);
         21 |
         22 |  const transfersTable = VueSelector('Transfer SingleAccountStatus v-data');
         23 |  await t.hover(transfersTable);
         24 |
       > 25 |  const transfersTableValues = await transfersTable.getVue();
         26 |  console.log(transfersTableValues);

[FR] Typings

Having typings would be great :)
The getVue method cannot be found and there are some problems with Selector vs SelectorPromise types.

Basic usage- Vue render content not available

Hi there,

I may be missing something obvious- but I have not been able to "find" any Vue components, aside from the initial wrapper.

For example:

In /main.js I'm importing "App" (which itself imports many components).

import Vue from "vue";
import App from "./App.vue";
...
new Vue({
  router,
  render: h => h(App),
  data:{
  	testing:1234
  }
}).$mount("#app");

When I run:

const rootVue = VueSelector();
const test= await rootVue.getVue();
console.log(test)

It logs:

{ props: {},
  state: { testing: 1234 },
  computed: {},
  ref: undefined }

However, if I try to specify anything else (such as app or any other components)- it tells me -

Cannot read property '__vue__' of undefined

For reference, this is what the vue developer tools show me:
Screen Shot 2019-07-15 at 4 53 30 pm

Could you please clarify how this is to be used?

Selector() failed to access "Row" of v-data-table of Vuetify

Selector() failed to access Row component in v-data-table of Vuetify.

Related to #52

Can anyone help me out to resolve this?

Environments

  • Chrome 89.0.4389.128 / macOS 11.2.3
  • node: v14.15.5
  • yarn: 1.22.10
  • testcafe: 1.14.0
  • testcafe-vue-selectors: 3.1.0
  • vuetify: 2.4.2

Test Codes tried

const transfersTableRow = VueSelector('Transfer SingleAccountStatus v-data-table row');
const transfersTableRow = VueSelector('Transfer SingleAccountStatus v-data-table row').nth(0);
const transfersTableRow = VueSelector('Transfer SingleAccountStatus v-data-table Row');
const transfersTableRow = VueSelector('Transfer SingleAccountStatus v-data-table Row').nth(0);

image

Results

 1) The specified selector does not match any element in the DOM tree.

       > | Selector([function])

      Browser: Chrome 89.0.4389.128 / macOS 11.2.3

         18 |    .typeText(amountInput, amount, { replace: true, paste: true })
         19 |    .click(transferButton)
         20 |    .click(proceedButton);
         21 |
         22 |  const transfersTableRow = VueSelector('Transfer SingleAccountStatus v-data-table row');
       > 23 |  await t.hover(transfersTableRow);

Unable to find a Vue componant within a named slot

Given the following template:

<template>
  <k-page padding>
    <template v-slot:page-content>
        <k-grid ref="membersGrid" service="members" :renderer="renderer" :contextId="contextId" :base-query="baseQuery" :filter-query="searchQuery" />
    </template>
  </k-page>
</template>

const pageVue= await VueSelector('k-page').getVue() works
const membersVue= await VueSelector('k-grid').getVue() doesnt' work and returns: getVue cannot return DOM elements. Use Selector functions for this purpose

Tested with:

  • TestCafe 1.8.5
  • testcafe-vue-selectors 3.1.0
  • vue 2.6.10

Implement base functionality

TODO:

  • search Roots
  • apply complex selector on vue's component tree
  • extend DOM Snapshot and expose vue specific properties

Test cases:

  • tag selector
  • complex selector
  • not vue component
  • vue doesn't find on page
  • supported versions

Can't get access to global Vue (Nuxt) object, fails with error.

Hi!
I'm trying to get access to root Vue (Nuxt) instance, but I can't:

const nuxt = await VueSelector();
const vm = await nuxt.getVue();
console.log(vm);

it fails with error:

1) getVue cannot return DOM elements. Use Selector functions for this purpose.

But recently, when I tried to use it with [email protected] it worked well, I could get root Vue (Nuxt) instance and read properties.

No matter if I use testcafe-vue-selectors or https://github.com/kartojal/testcafe-nuxt-selectors it fails in same way. Tried to dive deeper to TestCafe code, but didn't succeed.

Here's repo with reproduction instructions:
https://github.com/souljorje/TestCafe-nuxt-issue

Hope for your help!
Cheerz, Georgiy 🙌

Add note about running in development mode

VueSelector will work only if the Vue.js application was built in the development mode.
In the production mode, it is impossible to retrieve information about components (behavior like in the vue-devtools extension).

.getVue() seems not working

.getVue() method seems NOT working!

I can not find .getVue() in MS code. It shows "no definition for getVue()". Another problem is the TS7016: could not find the declaration file for testcafe-vue-selectors.

Waiting for an element to appear...

VueSelector can't seem to find a component by its tagName, causing the test to timeout. However, I can find the root instance.

Works (returns root instance)
const rootVue = await VueSelector().vue;

Works
const rightRail = await VueSelector('#right-rail').vue;

Timeout Error
const rightRail = await VueSelector('right-rail').vue;

Note, the component tagName is right-rail, which shows up in the dev tools as RightRail. The component template has an id of #right-rail.

Vue cmp state doens't seem to update

I'm trying to perform an action (delete a contact) while my the length contacts array is bigger than 0. But it seems that the state doesn't change after I deleted a contact.

The console log shows that the contact array length remains at one even though I delete a contact.

Am I doing something wrong or is there a way to my the state of my vue cmp reactive in TestCafe?

Thnx

const adviceAnalysisVueCmpState = await advicePage.step1.adviceAnalysis.getVue()
while (adviceAnalysisVueCmpState.computed.contacts.length > 0) {
    await t
    .click(advicePage.step1.deleteContact)
    .click(advicePage.step1.deleteFromAdvice)
    console.log(adviceAnalysisVueCmpState.computed.contacts.length, 2)
  }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.