I am currently studying cypress and as I was going through the tutorials one thing popped up in my mind. What if I wrote a small test case to, for example, open a website, click login and enter the credentials. Then I want to start a new test case to do something else on that website once logged in but on a different test case. Can I pull the information from the first one?
What I mean is this:
describe('My first test', function () {
it('login as user', function () {
cy.visit('https://uat2.myregus.com/home')
cy
.get('#header_LogIn').click()
.get('#Username').click()
.type('dogejaq#getairmail.com')
.type('{enter}')
.get('.password').click()
.type('Test_123!')
.type('{enter}')
})
})
Then my second case would pull the information from the above so that I can continue.
describe('My second test', function () {
it('book a meeting', function () {
cy.visit('https://uat2.myregus.com/home')
})
})
The reason I want to do this is because I don't want to run both tests every time. Essentially it would log me in every time using those credentials. I was thinking of making a separate .js file to pull from but I am not sure how. Please help.
Coupling multiple tests together is an anti-pattern. Your tests should always be able to be run independently from one another and still pass.
See docs from Cypress best practices here.
The code from your first test should be wrapped in a beforeEach hook so it can be run before each it():
describe('My second test', function () {
beforeEach(() => {
cy
.get('#header_LogIn').click()
.get('#Username').click()
.type('dogejaq#getairmail.com')
.type('{enter}')
.get('.password').click()
.type('Test_123!')
.type('{enter}')
})
it('book a meeting', function () {
cy.visit('https://uat2.myregus.com/home')
})
it('does something else', function () {
cy.visit('...')
})
})
You should also have a look at these logging in recipes to perform backend authentication instead of going through the UI to log in before each test.
Related
I'm using the cy.visit() command but the website i'm visiting (which i don't own) doesn't always fire the load event, although the content itself that i need for testing does appear on the website.
Despite the content appearing, since the load event is not fired sometimes (for some reason which i can't fix since i don't have ownership over this website), the cy.visit() command fails.
Is there a way to "force" it somehow, similar to how we can pass { force: true} for the cy.click() command?
Add the below to your cypress commands file
Cypress.Commands.add('forceVisit', url => {
cy.window().then(win => {
return win.open(url, '_self');
});
});
And in your tests, you can call
cy.forceVisit("www.google.com")
It's hard to simulate the problem, but I think I managed by setting pageLoadTimeout really low (30ms).
You can catch the onLoad fail in an event handler and checking for the page load error message.
I recommend doing it in a beforeEach().
beforeEach(() => {
Cypress.config("pageLoadTimeout", 30) // set this to whatever time length
// you feel is appropriate to start testing
// You'll need to experiment to get this right
// and in CI it will be a lot longer
cy.once('fail', (err) => { // "once" to just catch a single error
const message = err.parsedStack[0].message
if (message.match(/Timed out after waiting `\d+ms` for your remote page to load/)) {
return false
}
throw err // any other error, fail it
})
cy.visit('www.example.com');
})
it('checks the heading of the page', () => {
cy.get('h1').should('have.text', 'Example Domain') // ✅
})
As you can already assume, that is highly discouraged. It also really depends on how it fails and with which errors, but, without any code to reproduce, you may want to try this if you haven't already:
cy.visit('/', {failOnStatusCode: false});
Reference: https://docs.cypress.io/api/commands/visit#Arguments
I need to close the tab/window after each test so I can start the next from scratch
describe('theImplementationIamTesting', () => {
after(() => {
// CLOSE THE TAB AFTER THE TEST...
});
});
I am looking a way to close the current tab after the test. I am not talking about closing a child tab/window. I am talking about the initial tab.
In selenium, it will be something like webdriver.close().
I cannot find a single place online, including the cypress website, where it said how to close the tab browser.
Thanks for helping
If you separate the cases in different test files it will close the whole browser and reopen it every time. This is the only way I had found so far and works for me very well to start every case from scratch since sometimes it continues to run unfinished API requests from the first case after the start of the second case.
The downside is you need to make the initial preparation of the system every time and it increases the runtime.
The way I resolved this was to actually add an extra line at the end of each test which would click to navigate to a page from where the other tests could continue, say the 'home page'.
describe('Test Inline Text Entry Interactions', () => {
beforeEach('Log in as CypressEditor', () => {
cy.MockLoginUser('cypressEditor');
cy.visit('http://localhost:4200/homepage');
})
it('should test 1st thing', () => {
//Test something, then...
cy.get('#logo-label').click(); //To navigate back to http://localhost:4200/homepage
});
it('should test the 2nd thing', () => {
//Test something else...
cy.get('#logo-label').click(); //To navigate back to http://localhost:4200/homepage
});
it('should test the 3rd thing', () => {
//Test some more stuff, then...
cy.get('#logo-label').click(); //this might not be necessary since it's the last one.
});
For me this ensured that each test could finish and continue with the next.
Like in JUnit we have category annotation where we define regression, sanity name and set this category in pom.xml file to run only those Testcases. We dont need to change anything afterwards.
can we do same in Jasmine Protractor???
If we do have one file which is firstfile.ts
describe('angular-material paginator component page', () => {
const EC = protractor.ExpectedConditions;
beforeAll(async() => {
await browser.get('https://material.angular.io/components/paginator/examples');
});
it('Should navigate to next page', async() => {
await $('button[aria-label=\'Next page\']').click();
});
it('Should navigate to previous page', async() => {
await $('button[aria-label=\'Previous page\']').click();
});
it('Should change list length to 5 items per page', async() => {
await $('mat-select>div').click();
});
});
like this we have one more spec file and i want to set categories of the it block so i can write that only one word and run the test like in JUnit.
other than the option of f and x before describe and it block.
For annotation based execution you can try BDD in protractor with cucumber.
Here you can create features which can be organised and executed.
Refer this github repo : https://github.com/igniteram/protractor-cucumber-typescript.git
Please try to clone this repo and understand how it works.
I am using React for render and Jest/Jasmine for test. I have test written using old Jest/Jasmine waitsFor and runs but these are gone now in Jasmine 2 and I am not sure how to replace with new done asyncs.
In my code React renders a small page about a user. That page has an AJAX call to fetch user posts. I want to test that user posts have come back nice, and waitsFor was very, very good at this: wait until user has some post, then continue.
I looked online at lots of people talking about using AJAX calls inside Jest test which is not what I want. My Jest test has no idea about AJAX call being made, so I need a way to wait until results come back.
Here is my current code with waitsFor and runs:
it('loads user post', () => {
var page = TestUtils.renderIntoDocument(
<UserPage params={{user: 'fizzbuzz', 'pass': 'xxx'}} />
);
waitsFor(() => {
return page.state.posts.length > 0;
}, "post loaded", 10000);
runs(() => {
var posts = TestUtils.scryRenderedDOMComponentsWithClass(page, 'post');
expect(posts.length).toEqual(10);
});
});
How can I delete the waitsFor and runs and replace with Jasmine 2.0 code that works? All Jest test knows is that page.state.posts.length must be greater than 0 before expecting anything.
You should refactor this test into two unit tests that will provide a more rigorous testing of your code. It would make the tests more independent of one another and help identify errors in a more refined scope. These won't be exact as I do not know what your code is like, but here's something along the lines I would expect to see: -
it('generates the expected properties for a page', function () {
var page = TestUtils.renderIntoDocument(
<UserPage params={{user: 'fizzbuzz', 'pass': 'xxx'}} />
);
expect(page.someProperty).toBeDefined();
expect(page.user).toEqual('fizzbuzz');
});
it('generates the correct number of posts from a given page object', function () {
var fakePage = {
// put your fake mock data here that TestUtils expects
};
var posts = TestUtils.scryRenderedDOMComponentsWithClass(fakePage, 'post');
expect(posts.length).toEqual(10);
});
I am not too sure what is happening in your renderIntoDocument function so the top test may be a little broken... It looks like there is either too much going on inside the function, or you need to test the calls that function is making instead. If you elaborate on what it does I'll edit the answer.
Lets say we have a form with a jquery validation. Now we create a simple Jasmine spec and want to test if the error message is visible if we submit an empty form.
My first step is to trigger the submit form event after that jquery validate will work and show the error messages. The time window until the error message will be displayed is really small (2ms) but too big for a Jasmine test. Currently with a setTimeout() it works but I think that is a bad way :(
I am new to Jasmine and I think there must be a better way? Something with spy?
Dummy spec for example:
describe("Lorem Impsum: ", function () {
it("Form validation shows error messages.", function () {
$("#MyForm").submit();
expect($(".error")).toBeVisible();
});
});
Using setTimeout or setInterval for polling may not be a bad way. If the page is complicated, periodic checks are simpler, than using MutationObserver. (This is a unit test; not an application.) If you choose the polling interval short enough, the test will not be so slow. For example:
describe("Lorem Impsum: ", function () {
it("Form validation shows error messages.", function (done) {
$("#MyForm").submit();
waitForElement(".error", function () {
expect($(".error")).toBeVisible();
done();
});
});
});
function waitForElement(selector, callback) {
var interval;
if ($(selector).length) {
callback();
} else {
interval = setInterval(function () {
if ($(selector).length) {
clearInterval(interval);
callback();
}
}, 10);
}
}
You will need to declare and call the done callback, so that Jasmine gets notified, when the test spec has finished.