I am new in cypress, I want to create a dynamic method that returns the text of whatever DOM element pass on it, so I have created one but it returns some unexpected result please see the below code and suggest to me where I am doing wrong or what is the best option for achieving this task.
login_objrepo.json
{
"Signin_lbl":".login100-form-title.p-b-10" //Locator
}
Login.sepc.js
import commonUtility from "../../support/commonUtility";
const util = new commonUtility();
const objLogin = require('../../fixtures/login_objrepo');
describe('Login Page', function () {
it('Verify Page', () => {
util.openUrl(objLogin.URL);
const exp = 'Sign In';
const act = util.getText(objLogin.Signin_lbl);
cy.log("Exp title=" + exp + " and Act=" + act)
cy.get(objLogin.Signin_lbl).should('have.text',exp);
})
})
commonUtility.js
class commonUtility
{
getText(locator)
{
cy.wait(3000);
cy.get(locator).then(($attribute)=> {
let txt=$attribute.text();
cy.log("Retun Text is = "+ txt);
})
return this;
}
}
here (txt variable) got the valid text but, in the above file(Login.sepc.js) were to call it there showing ([object Object])... how to get the same here also?
==========================
OUTPUT
Use a .then() to extract the text value from the returned [object Object],
class commonUtility {
getText(locator) {
return cy.get(locator).then(($element) => { // return cy.get not "this"
let txt = $element.text();
return txt // in here, return txt
})
}
}
describe('Login Page', function () {
it('Verify Page', () => {
util.openUrl(objLogin.URL);
const exp = 'Sign In';
util.getText(objLogin.Signin_lbl).then((act) => { // extract txt from [object Object]
console.log("Exp title=" + exp + " and Act=" + act)
})
cy.get(objLogin.Signin_lbl).should('have.text', exp);
})
})
Related
I have a custom plugin in ckeditor5.
When user click on toolbar icon my plugin convert selected test to custom element with a custom attribute name comment-id.
this work properly.
Now I want to watch on click element and get comment-id on click and I don't know how can I do that.
this is the code of my custom plugin
import uploadIcon from './message.svg'
import ButtonView from '#ckeditor/ckeditor5-ui/src/button/buttonview'
import Plugin from '#ckeditor/ckeditor5-core/src/plugin'
import Command from '#ckeditor/ckeditor5-core/src/command'
import './comment.css'
export default class CustomFileExporerPlugin extends Plugin {
init() {
const editor = this.editor
const config = editor.config.get('comment')
console.log(editor.editing.view.document.isFocused)
editor.editing.view.document.on('click', a => {
console.log(a)
})
editor.model.schema.extend('$text', { allowAttributes: 'comment' })
editor.conversion.attributeToElement({
model: 'comment',
view: (commentId, writer) => {
debugger
if (writer) {
return writer.writer.createAttributeElement(
'comment',
{
'comment-id': commentId,
class: `ck-comment-marker`
},
{ priority: 5 }
)
}
}
})
editor.commands.add('comment', new CommentCommand(editor))
editor.ui.componentFactory.add('comment', locale => {
const view = new ButtonView(locale)
view.set({
label: 'add comment',
icon: uploadIcon,
tooltip: true
})
view.on('execute', async () => {
editor.editing.view.focus()
let id = await config.callback()
editor.execute('comment', { value: 'comment', id })
})
return view
})
}
}
class CommentCommand extends Command {
refresh() {
const model = this.editor.model
const doc = model.document
this.value = doc.selection.getAttribute('comment')
this.isEnabled = model.schema.checkAttributeInSelection(
doc.selection,
'comment'
)
}
execute(options = {}) {
const model = this.editor.model
const document = model.document
const selection = document.selection
const highlighter = options.value
model.change(writer => {
const ranges = model.schema.getValidRanges(
selection.getRanges(),
'comment'
)
if (selection.isCollapsed) {
const position = selection.getFirstPosition()
if (selection.hasAttribute('comment')) {
const isSameHighlight = value => {
return (
value.item.hasAttribute('comment') &&
value.item.getAttribute('comment') === this.value
)
}
const highlightStart = position.getLastMatchingPosition(
isSameHighlight,
{ direction: 'backward' }
)
const highlightEnd = position.getLastMatchingPosition(isSameHighlight)
const highlightRange = writer.createRange(
highlightStart,
highlightEnd
)
writer.removeAttribute('comment', highlightRange)
writer.removeSelectionAttribute('comment')
} else if (highlighter) {
writer.setSelectionAttribute('comment', highlighter)
}
} else {
for (const range of ranges) {
writer.setAttribute('comment', options, range)
}
}
})
}
}
When rendering editor, you can catch custom plugin click event using below code.
const command = editor.commands.get('comment')
command.on('execute', () => { catch click event in custom plugin})
I try to create a delete method in vue-tags-input in Vue Js. I am not sure how to get the index. from this tag. Usually in my delete method I use the index .
<vue-tags-input
v-model="tagName"
class="tags-input w-100 mt-0"
#before-deleting-tag="deleteCustomerName"
/>
deleteCustomerName: function () {
const id = this.editedItemId;
const id_c = 33; //right now I am not sure how to get id_c
// const deleted_user_name = this.customer_names[index].name;
this.boxOne = "";
this.$bvModal
.msgBoxConfirm("Are you sure that you want to delete this ?", {
okVariant: "danger",
okTitle: "Delete",
cancelTitle: "Cancel",
centered: true
})
.then(confirm => {
if (confirm) {
deleteApi("/customers/" + id + "/" + id_c).then(() => {
this.$nextTick(() => {
// this.$emit('deleted',deleted_user_name)
// this.customer_names.splice(index, 1); //usualy I do this, but now it doesn't now how index is
console.log('User deleted!');
});
});
}
})
.catch(error => {
console.log(error);
});
},
Here is describing http://www.vue-tags-input.com/#/api/events . before-deleting-tag return index,tag,deleteTag[func] so you need to set param in deleteCustomerName parameters scope .
deleteCustomerName: function (params) {
console.log(params.index)
....
}
I'm in trouble I'm trying to pass information that gets from an api rest that's in a component A and store it in a variable of a B component
i've dealt with this:
Componente A:
data: () => {
return {
server: []
};
}
axios
.post("http://0.tcp.ngrok.io:13601//accountmanagement/login", LogInUser)
.then(res => {
this._UserLogin = res.data;
if (
this._UserLogin.credencial.rol.id_rol == 1 &&
this._UserLogin.credencial.correo == LogInUser.correo
) {
this.$router.push("admin");
} else if (
this._UserLogin.credencial.rol.id_rol == 2 &&
this._UserLogin.credencial.correo == LogInUser.correo
) {
this.$router.push("usuario");
this.server = this._UserLogin
//here I try to send the already verified user to another
component clear the request returns me a json if correct if
the registration is correct:
EventBus.$emit('serverSelected', this.server);
}
})
.catch(resError => {
alert(
"El servidor es en mantenimiento por favor intente mas tarde" +
resError
);
});
Component B:
data: () => {
return {
server: []
};
}
created() {
EventBus.$on(
"serverSelected",
function(serve) {
this.server = serve;
console.log("The person is: ", this.server);
}.bind(this)
);
}
including this does not show me any error or print me the information of the record that I try to send by eventBus.emit
Call eventBus:
import eventBus from '../../evenbus'
evenbus content:
import Vue from 'vue';
export const EventBus = new Vue();
I have been trying to create my own custom chai assertion (based on the Cypress recipe template: https://github.com/cypress-io/cypress-example-recipes/blob/master/examples/extending-cypress__chai-assertions/cypress/support/index.js).
What I have found with the code below is that when it is run I end up with a constant loop of WRAP, if I swap this.obj with element it then results in a constant stream of GET. I do not seem to ever progress further than getRect(first).then((actual)
If anyone could help me out I'd be very grateful.
cypress/integration/test.js
describe('testing custom chai', () => {
it('uses a custom chai helper', () => {
cy.visit('https://www.bbc.co.uk/news');
cy.get('#orb-modules > header').should('be.leftAligned', '#orb-header');
});
});
cypress/support/index.js
function getRect(selector) {
if (selector === '&document') {
return cy.document().then(doc => doc.documentElement.getBoundingClientRect());
} if (typeof selector === 'string') {
return cy.get(selector).then($elem => $elem[0].getBoundingClientRect());
}
return cy.wrap(selector).then(elem => Cypress.$(elem)[0].getBoundingClientRect());
}
function getRects(first, second) {
return getRect(first).then((actual) => {
getRect(second).then(expected => [actual, expected]);
});
}
const aligned = (_chai, utils) => {
function leftAligned(element) {
getRects(element,this.obj).then((rects) => {
this.assert(
rects[0].left === rects[1].left,
'expected #{this} to be equal',
'expected #{this} to not be equal',
this._obj,
);
});
}
_chai.Assertion.addMethod('leftAligned', leftAligned);
};
chai.use(aligned);
The basic problem is that the async commands cy.get(), cy.wrap(), cy.document() can't be used in the custom assertion. My best guess is that the auto-retry mechanism is going bananas and giving you the constant loop.
Instead, you can use Cypress.$() which is the synchronous version (essentially jquery exposed on the Cypress object).
The following seems to work ok. (I renamed getRects() param to subject, as sometimes it's a selector and sometimes it's the object passed in to .should()).
Note also this._obj instead of this.obj.
function getRect(subject) {
if (subject === '&document') {
return Cypress.$(document).context.documentElement.getBoundingClientRect();
}
if (typeof subject === 'string') { // the selector passed in to assertion
return Cypress.$(subject)[0].getBoundingClientRect();
}
if (typeof subject === 'object') { // the element from cy.get() i.e this._obj
return subject[0].getBoundingClientRect();
}
return null; // something unkown
}
function getRects(first, second) {
const actual = getRect(first)
const expected = getRect(second)
return [actual, expected];
}
const aligned = (_chai, utils) => {
function leftAligned(element) {
const rects = getRects(element, this._obj)
this.assert(
rects[0].left === rects[1].left,
'expected #{this} to be equal',
'expected #{this} to not be equal',
this._obj,
);
}
_chai.Assertion.addMethod('leftAligned', leftAligned);
};
chai.use(aligned);
I was unable to test your BBC page directly, as there's a cross-origin problem occurring
Refused to display 'https://www.bbc.com/news' in a frame because it set 'X-Frame-Options' to 'sameorigin'
but it does work with a mockup page
cypress/app/bbc-sim.html
<div id="orb-modules">
<header>
<h1>Brexit: Boris Johnson's second attempt to trigger election fails</h1>
</header>
</div>
and testing like so
it('uses a custom chai helper', () => {
cy.visit('app/bbc-sim.html')
cy.get('#orb-modules > header').should('be.leftAligned', '#orb-modules');
});
just trying come silly stuff and playing around with Cycle.js. and running into problem. Basically I just have a button. When you click it it's suppose to navigate the location to a random hash and display it. Almost like a stupid router w/o predefined routes. Ie. routes are dynamic. Again this isn't anything practical I am just messing with some stuff and trying to learn Cycle.js. But the code below crashes after I click "Add" button. However the location is updated. If I actually just navigate to "#/asdf" it displays the correct content with "Hash: #/asdf". Not sure why the flow is crashing with error:
render-dom.js:242 TypeError: Cannot read property 'subscribe' of undefined(…)
import Rx from 'rx';
import Cycle from '#cycle/core';
import { div, p, button, makeDOMDriver } from '#cycle/dom';
import { createHashHistory } from 'history';
import ranomdstring from 'randomstring';
const history = createHashHistory({ queryKey: false });
function CreateButton({ DOM }) {
const create$ = DOM.select('.create-button').events('click')
.map(() => {
return ranomdstring.generate(10);
}).startWith(null);
const vtree$ = create$.map(rs => rs ?
history.push(`/${rs}`) :
button('.create-button .btn .btn-default', 'Add')
);
return { DOM: vtree$ };
}
function main(sources) {
const hash = location.hash;
const DOM = sources.DOM;
const vtree$ = hash ?
Rx.Observable.of(
div([
p(`Hash: ${hash}`)
])
) :
CreateButton({ DOM }).DOM;
return {
DOM: vtree$
};
}
Cycle.run(main, {
DOM: makeDOMDriver('#main-container')
});
Thank you for the help
I would further suggest using #cycle/history to do your route changing
(Only showing relevant parts)
import {makeHistoryDriver} from '#cycle/history'
import {createHashHistory} from 'history'
function main(sources) {
...
return {history: Rx.Observable.just('/some/route') } // a stream of urls
}
const history = createHashHistory({ queryKey: false })
Cycle.run(main, {
DOM: makeDOMDriver('#main-container'),
history: makeHistoryDriver(history),
})
On your function CreateButton you are mapping your clicks to history.push() instead of mapping it to a vtree which causes the error:
function CreateButton({ DOM }) {
...
const vtree$ = create$.map(rs => rs
? history.push(`/${rs}`) // <-- not a vtree
: button('.create-button .btn .btn-default', 'Add')
);
...
}
Instead you could use the do operator to perform the hashchange:
function CreateButton({ DOM }) {
const create$ =
...
.do(history.push(`/${rs}`)); // <-- here
const vtree$ = Observable.of(
button('.create-button .btn .btn-default', 'Add')
);
...
}
However in functional programming you should not perform side effects on you app logic, every function must remain pure. Instead, all side effects should be handled by drivers. To learn more take a look at the drivers section on Cycle's documentation
To see a working driver jump at the end of the message.
Moreover on your main function you were not using streams to render your vtree. It would have not been reactive to locationHash changes because vtree$ = hash ? ... : ... is only evaluated once on app bootstrapping (when the main function is evaluated and "wires" every streams together).
An improvement will be to declare your main's vtree$ as following while keeping the same logic:
const vtree$ = hash$.map((hash) => hash ? ... : ...)
Here is a complete solution with a small locationHash driver:
import Rx from 'rx';
import Cycle from '#cycle/core';
import { div, p, button, makeDOMDriver } from '#cycle/dom';
import { createHashHistory } from 'history';
import randomstring from 'randomstring';
function makeLocationHashDriver (params) {
const history = createHashHistory(params);
return (routeChange$) => {
routeChange$
.filter(hash => {
const currentHash = location.hash.replace(/^#?\//g, '')
return hash && hash !== currentHash
})
.subscribe(hash => history.push(`/${hash}`));
return Rx.Observable.fromEvent(window, 'hashchange')
.startWith({})
.map(_ => location.hash);
}
}
function CreateButton({ DOM }) {
const create$ = DOM.select('.create-button').events('click')
.map(() => randomstring.generate(10))
.startWith(null);
const vtree$ = Rx.Observable.of(
button('.create-button .btn .btn-default', 'Add')
);
return { DOM: vtree$, routeChange$: create$ };
}
function main({ DOM, hash }) {
const button = CreateButton({ DOM })
const vtree$ = hash.map(hash => hash
? Rx.Observable.of(
div([
p(`Hash: ${hash}`)
])
)
: button.DOM
)
return {
DOM: vtree$,
hash: button.routeChange$
};
}
Cycle.run(main, {
DOM: makeDOMDriver('#main-container'),
hash: makeLocationHashDriver({ queryKey: false })
});
PS: there is a typo in your randomstring function name, I fixed it in my example.