I'm using Cypress to test a website.
When I use xpath inside cy.origin(), It's not working.
it('t1', function() {
cy.origin(('BaseUrl'), () => {
cy.visit('/profile')
cy.xpath("//input[#name='username']").type('user')
cy.xpath("//input[#name='password']").type('pass')
cy.xpath("//button[#type='button']").click()
})
})
Error:
TypeError
cy.xpath is not a function
Note that it works correctly outside cy.origin()
TLDR: Stick with standard Cypress commands inside cy.origin().
It's a current limitation of cy.orgin(), in fact any custom command must be treated specially and cy.xpath() is a custom command.
See Callback restrictions
It is also currently not possible to use require() or dynamic import() within the callback. Because of this limitation, it cannot use npm packages or other third-party libraries inside the callback, as there is no mechanism to reference them. This functionality will be provided in a future version of Cypress.
While third-party packages are strictly unavailable, it is possible to reuse your own code between cy.origin() callbacks. The workaround is to create a custom Cypress command within the secondary origin in a before block:
before(() => {
cy.origin('somesite.com', () => {
Cypress.Commands.add('clickLink', (label) => {
cy.get('a').contains(label).click()
})
})
})
it('clicks the secondary origin link', () => {
cy.origin('somesite.com', () => {
cy.visit('/page')
cy.clickLink('Click Me')
})
})
But you can't use this pattern with cy.xpath() as you currently need to require('cypress-xpath') and that can't be done inside cy.origin().
A Workaround
Navigate to /node_modules/cypress-xpath/src/index.js
Copy the entire contents
Add a new command file in support: /cypress/support/xpath.js
Add this to the file, pasting in the copied code
before(() => {
cy.origin('somesite.com', () => { // your cross-origin URL here
// paste here code from /node_modules/cypress-xpath/src/index.js
})
})
Import xpath.js into /cypress/support/commands.js
Now cy.xpath() will work within cy.orgin() in any of your tests.
Check to see if non-xpath works.
cy.origin(('BaseUrl'), () => {
cy.visit('/profile')
cy.get("input[#name='username']").type('user')
...
If not, you've probably not set the experimentalSessionAndOrigin flag correctly.
Related
I have a problem with a wildcard page /pages/[...slug].vue and fetching from backend.
I have a computed called url that I use in:
const { data, refresh } = await useFetch(url.value)
Then I have a watcher to refresh the useFetch:
watch(url, (url, oldUrl) => {
console.log(url)
console.log(oldUrl)
refresh()
})
In the browser, the console log shows the correct url, but useFetch just loaded the old url again.
Any idea what's wrong here? Thanks.
[edit: clarification: this is when navigation in browser, that triggers the watch]
I believe because computed is a 'getter' behind the scenes you need to use a deep watcher on it or watch the returned value directly otherwise the watch function will not run.
You could change your watch function to to:
watch(url, (url, oldUrl) => {
console.log(url)
console.log(oldUrl)
refresh()
},
{ deep: true }
)
Alternatively you could directly watch the value of the computed property:
watch( () => url.value, (url, oldUrl) => {
console.log(url)
console.log(oldUrl)
refresh()
},
{ deep: true }
)
There is a bit more information here: https://vuejs.org/guide/essentials/watchers.html#basic-example
Hi i had the same issue 2 days ago.. i guess that the issue happens because of the default keep alive props and internal caching.
My solution was to use $fetch() instead of useFetch().
Like that you also don't need the watcher anymore.
I want Cypress to go through every page to see on a website to see if there are any console errors and if so, make it known to the user running the test. (I'm thinking it would be useful for CSP checking to see if the site is throwing a console error because of a domain not being whitelisted.)
This package cypress-fail-on-console-error
may make it easier
test
import failOnConsoleError from 'cypress-fail-on-console-error';
failOnConsoleError();
const pages = [ "/page1", "/page2" ]
pages.forEach(page => {
it(`verifies the page ${page}`, () => {
cy.visit(page)
})
})
There's some interesting stuff on Cypress and CSP here
Testing Content-Security-Policy using Cypress ... Almost
You can use a combination of Cypress functionality to achieve this. You could store the list of links in an array of strings, use Cypress Lodash to iterate through each string as a separate test, and use the onBeforeLoad callback within cy.visit() to spy on console.error.
describe('Tests', () => {
// Define links
const links = ['/1', '/2', '/3'...]
// Iterate through the links array using Cypress Lodash
Cypress._.times(links.length, (index) => {
it('validates site loads with no errors', () => {
cy.visit(links[index], {
// set the `onBeforeLoad` callback to save errors as 'error'
onBeforeLoad(win) {
cy.stub(win.console, 'error').as('error');
}
});
// Validate error was not called
cy.get('#error').should('not.have.been.called');
});
});
});
A good deal of this answer was taken from this answer.
If you'd like to be specific about the errors that fail, try catching uncaught:exception
Cypress.on('uncaught:exception', (err) => {
if (err.message.includes('Content Security Policy')) {
return true
} else {
return false // only fail on the above message
}
})
describe('Testing Content Security Policy', () => {
const pages = [ "/page1", "/page2" ]
pages.forEach(page => {
it(`visiting page ${page}`, () => {
cy.visit(page)
})
})
})
I've had a few errors trying to render single blog posts.
I tried using the page template with /post/{post_name} and I was getting this error:
warn Non-deterministic routing danger: Attempting to create page: "/blog/", but
page "/blog" already exists
This could lead to non-deterministic routing behavior
I tried again with /blog/{post_name}.
I now have both routes, which I'm not sure how to clean up; but more importantly, on those pages, nothing renders, even though there should be an h1 with it's innerhtml set to the node.title and likewise a div for the content.
I've uploaded my config and components to https://github.com/zackrosegithub/gatsby so you can have a look.
Not sure how to fix
I just want to see my content rendered on the screen.
Developer tools don't seem to help when there's no content rendered as I can't find anything to inspect to try to access it another way.
Thank you for your help
Your approach is partially correct. You are using a promise-based approach but when using then() you are already settling and partially resolving it so you don't need to use the callback of resolve(), which may be causing a duplication of the promise function so try removing it.
Additionally, you may want to use a more friendly approach using async/await functions. Something like:
exports.createPages = async ({ graphql, actions, reporter }) => {
const yourQuery= await graphql(
`
{
allWordpressPost {
edges{
node{
id
title
slug
excerpt
content
}
}
}
}
`
if (yourQuery.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`);
return;
}
const postTemplate = path.resolve("./src/templates/post.js")
_.each(yourQuery.data.allWordpressPost.edges, edge => {
createPage({
path: `/post/${edge.node.slug}/`,
component: slash(postTemplate),
context: edge.node,
})
})
})
// and so on for the rest of the queries
};
In addition, place a console.log(pageContext) in your postTemplate to get what's reaching that point and name the template as:
const Post = ({pageContext}) => {
console.log("your pageContext is", pageContext);
return <div>
<h1>
{pageContext.title}
</h1>
</div>
}
export default Post;
I have mainly worked with cypress previously for e2e automated testing, I have now started working on webdriverIO. So for a cypress command such as
cy.get("[data-testid='nav-bar']").contains("Search Box").click();
What would be the equivalent for this in webdriverIO? I have tried the following approach in a PageObject Model.
class HomePage extends Page {
get navBar() {
return browser.$("[data-testid='nav-bar']");
}
openSearchBox() {
this.navBar().click('//*[text="Search Box"]');
}
}
However, this approach does not seem to work, any help on this would be appreciated.
Leaving Page Objects asside for now, you'd type this in WebdriverIO:
const bar = $('[data-testid='nav-bar']');
expect(bar.getText()).toInclude('Search Box');
bar.click();
You can use chai for the assertion instead of Jest Matchers:
const expectChai = require('chai').expect;
// ...
expectChai(bar.getText()).to.have.string('Search Box');
// ...
The exact analog to
cy.get("[data-testid='nav-bar']").contains("Search Box").click();
can be achieved with xpath selector
$("[data-testid='nav-bar']").$("./*[descendant-or-self::*[contains(text(), 'Search Box')]]").click();
It looks a bit ugly though, consider adding a custom command that would mimic Cypress's contains:
// put this to `before` hook in your wdio.conf.js
browser.addCommand('cyContains', function(text) {
this.waitForExist()
return this.$(`./*[descendant-or-self::*[contains(text(), '${text}')]]`)
}, true)
$("[data-testid='nav-bar']").cyContains("Search Box").click();
P.S.
Check out the selector in the browser console right on this page, paste in the browser console
$x("//span[descendant-or-self::*[contains(text(), 'Search Box')]]")
When I try to modify pages/_document.js to add the FastClick event registration (see below) it complains that ReferenceError: document is not defined. I guess it's because it's executed on the server and the document is not defined there. Any way to resolve it?
if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body)
}, false)
}
pages/_document.js only rendered on server according to next.js documentation.
I suggest to use that code in pages/_app.js which will be shared between all components.
you can use process.browser to make sure your code is being executed in the front end only.
if (process.browser) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body)
}, false)
}