How pass a login form with CYPRESS? - javascript

I manage to run CYPRESS without any worries on a site without authentication.
But on an intranet, I can't identify myself. I must to log in before.
Here is my code:
describe('home', () => {
it('home accessible', () => {
cy.visit('/')
})
//We fill the login FORM
it('User Field', () => {
cy.get('input#user')
.type('login')
})
it('User pass', () => {
cy.get('input#pass')
.type('mot de passe')
})
it('check consent', () => {
cy.get('input#permalogin')
.click({ force: true })
})
it('submit', () => {
cy.get('input.btn.btn-primary')
.click()
})
//the form is submit, we can visit a page
it('autre page!!', () => {
cy.visit('/luniversite/page-2',{ timeout: 30000 })
})
//We check the title of the page, we should be on the page 2
it('titre page 2', () => {
cy.title().should('eq', 'page 2: INTRANET)
})
CYPRESS and the CYPRESS video show me that I am blocked on the authentication page.
The test on the title of the page is not correct, I don't access page-2. I stay on the first page for log in.

First thing's first: This appears to be one test, but you are specifying multiple it() functions, which is breaking it up into multiple tests, which is not what you want. You will want to restructure your test like this:
describe("home", () => {
it("home accessible", () => {
cy.visit("/");
//We fill the login FORM
cy.get("input#user").type("login");
cy.get("input#pass").type("mot de passe");
cy.get("input#permalogin").click({ force: true });
cy.get("input.btn.btn-primary").click();
cy.visit("/luniversite/page-2", { timeout: 30000 });
cy.title().should("eq", "page 2: INTRANET");
});
});
With that out of the way, it's hard to know what your application is doing without more details:
1/ When executed manually, is your application authenticating properly with the provided credentials? Do you have console errors? Have you determined that the element locators you're using are actually interacting with the elements in the manner you expect?
2/ Is your test attempting to navigate to /luniversite/page-2 before authentication is complete? If so, you may want to use intercept your authentication call and wait for it to complete:
// get your authentication POST request from network tab of devtools and use that in the cy.intercept call
cy.intercept('POST', '/yourAuthenticationCallUrl').as("#authenticationCall")
// YOUR LOGIN STEPS HERE
cy.wait("#authenticationCall") //waits for the authentication call to complete before moving to the next step
cy.visit("/luniversite/page-2", { timeout: 30000 });

Related

Cypress not intercepting request with render function vue

I'm trying to do a pretty simple intercept in Cypress using a Vue's application. My component has a setup method using render function as such:
setup() {
useInfiniteLoading({ runner: ... })
}
Then on my tests I do the following:
describe("List todo resource", () => {
it("Checks it loads more todos when scrolling to the bottom", function () {
cy.intercept('/todo').as('getTodos');
cy.visit("/todos");
cy.wait("#getTodos").then(({response}) => {
console.log(response);
})
})
})
When running the test I see that the intercept is not stubbing the response.
As you can see from the image the request makes a request to my actual server running locally and the response is stubed. The weird part is that in a previous test I have:
it("Checks the todo list gets updated when clicking on to resolve it (from true to false)", function () {
cy.visit("/todos");
const resolved = false;
const shouldHaveClass = resolved
? "mdi-checkbox-marked-outline"
: "mdi-checkbox-blank-outline";
cy.intercept("GET", "todo", {
fixture: "resources/todo/list.todo.json",
}).as("getTodos");
cy.intercept("PUT", "todo", {
body: { data: { ...this.updateTodoFixture.data, resolved } },
}).as("updateTodo");
cy.get(".todo-list-item__resolve")
.first()
.each((btn) => {
btn.click();
});
cy.get(".todo-list-item__resolve")
.first()
.should("satisfy", ($el) => {
const classList = Array.from($el[0].classList);
return classList.includes(shouldHaveClass);
});
});
And the response is stubbed using intercept as you can see from the previous screenshot. Is it possible that the previous test is affecting the next test? I have tried taking a look into "Intercept too soon" but no luck on trying to apply the fix described in the page.
Any idea on what could be causing the stub not to happen?

in cypress, intercept in test doesn't work

I'm starting to use cypress and I wanted to do 2 test. One to verify what is displayed if my api return 'false' and one to what is on screen if my api return 'true'.
I tried to do a simple test like this one :
context('contextTest', () => {
before(() => {
cy.waitLoading();
});
beforeEach(() => {});
it('false test', function() {
cy.intercept('POST', '**/test/alreadySent', {
fixture: 'test/alreadySent-false.json',
}).as('alreadySent');
cy.wait('#alreadySent');
cy.get('[data-cy=alreadysent-button]');
});
});
But the intercept doesn't work and it always return the true api call.
What is strange is, if I just put the code in my before(), all work fine as expected.
context('contextTest', () => {
before(() => {
cy.intercept('POST', '**/test/alreadySent', {
fixture: 'test/alreadySent-false.json',
}).as('alreadySent');
cy.waitLoading();
});
beforeEach(() => {});
it('false test', function() {
cy.wait('#alreadySent');
cy.get('[data-cy=alreadysent-button]');
});
});
But I need to change the intercept for the next test so I wanted to set the intercept on this test exclusively.
Is it possible, why is my first code doesn't seem to work?
Or should I write my next test on another file and it is a bad practice to do this kind of verification on the same file?
Since it works when the intercept is moved up in the command order, it seems that cy.waitLoading() triggers the POST and not cy.get('[data-cy=alreadysent-button]').
The intercept must always be set up before the trigger (page visit or button click).
But the intercept varies between tests, so instead of before() I would try setting up a helper function that is called at the top of each test.
const loadAndIntercept = (apiResult) => {
const apiFixture = apiResult ? 'test/alreadySent-true.json' : 'test/alreadySent-false.json';
cy.intercept('POST', '**/test/alreadySent', { fixture: apiFixture }).as('alreadySent');
cy.waitLoading();
})
it('false test', function() {
loadAndIntercept(false);
cy.wait('#alreadySent');
cy.get('[data-cy=alreadysent-button]');
});
it('true test', function() {
loadAndIntercept(true);
cy.wait('#alreadySent');
cy.get('[data-cy=alreadysent-button]');
});
This should work since intercepts are cleared between tests. Ref docs - intercept
Note: all intercepts are automatically cleared before every test.

Looking for alternatives to cy.wait() on a flaky test in Cypress

So I have a flaky test case right now in Cypress. When the modal loads, it skips the filling out the name part but fills out everything else. Therefore, causing it to fail the first time, but on the retry, it passes. I tried adding an assertion (see below), but it does not work. I am trying to avoid adding using a wait command, but wanted to see if there are any other alternatives out there to cy.wait().
describe("Coach dealing with forms" () => {
beforeEach(() => {
loginfile.login(users.coach)
});
it("Can fill out form and submit", () => {
cy.get("#modal-button").click()
cy.get("#modal-form").should("exist")
cy.get("#form-name").type("Mike Johnson")
cy.get("#form-age").type("33")
cy.get("#form-email").type("mj09#yahoo.com)
cy.get("#submit-button").click()
}
}
There a number of ways to approach flaky tests. You can try these and check what suits best for your use case:
1.Test Retires easy and effective, just retry the execution automatically it something fails. Can be applied, globally using cypress.json or to a describe block or to a it block as well.
For it block:
// `it` test block with custom configuration
it('allows user to login', {
retries: {
runMode: 2,
openMode: 2
}
}, () => {
// ...
})
For describe block:
// Customizing retry attempts for a suite of tests
describe('User bank accounts', {
retries: {
runMode: 2,
openMode: 2,
}
}, () => {
// The per-suite configuration is applied to each test
// If a test fails, it will be retried
it('allows a user to view their transactions', () => {
// ...
}
it('allows a user to edit their transactions', () => {
// ...
}
})
2.Adding .visible and click() before writing into the name field
it("Can fill out form and submit", () => {
cy.get("#modal-button").click()
cy.get("#modal-form").should("exist")
cy.get("#form-name").should('be.visible') //making sure the name field is visible
cy.get("#form-name").click() //clicking on the name field
cy.get("#form-name").type("Mike Johnson")
cy.get("#form-age").type("33")
cy.get("#form-email").type("mj09#yahoo.com")
cy.get("#submit-button").click()
})
3.Use timeouts instead of waits
cy.get("#form-name", {timeout: 10000}).type("Mike Johnson")
4.Use cy.intercept() to wait for the XHR request to finish execution. Here I am assuming that there is some unfinished XHR request after clicking the modal button that is causing the issue. If that is not the case, you can debug your tests to find out and apply intercept accordingly.
it("Can fill out form and submit", () => {
cy.intercept('http://example.com/settings').as('getSettings') //Intercept the url that is triggered after clicking the modal button
cy.get("#modal-button").click()
cy.wait('#getSettings') //Wait till that request has finished execution
cy.get("#modal-form").should("exist")
cy.get("#form-name").type("Mike Johnson")
cy.get("#form-age").type("33")
cy.get("#form-email").type("mj09#yahoo.com")
cy.get("#submit-button").click()
})
You should add a timeout to the type() command (not to the get() command) and follow it with a should() to confirm the value has been entered.
type() and should() will both retry until they succeed.
it("Can fill out form and submit", () => {
cy.get("#modal-button").click()
cy.get("#modal-form") // .should("exist") - don't need as cy.get() does that already
cy.get("#form-name").type("Mike Johnson", {timeout: 10000}) // wait for actionability
.should('have.value', 'Mike Johnson');
cy.get("#form-age").type("33")
cy.get("#form-email").type("mj09#yahoo.com")
cy.get("#submit-button").click()
})

How can we ignore the openHash value in cy.route() request send

In Cypress I am using cy.route() for sending the below request, but cypress is not identifying the below request send. In the route url there is a openHash value which will be different for every POST request. Is there any way to ignore the openHash value or accept what ever value displays there.
So far I have tried by giving the url in following ways in route.
url: '**/student/details.php?viewDetails=project&stdCount=1&sectionID=1&openHash=**',
url: '**/student/details.php?viewDetails=project&stdCount=1&sectionID=1&openHash=**&ajaxCall=true**',
I believe while using cy.route() the POST url need to match exactly. Could someone please advise
Cypress version: 5.4.0
Student.feature
Feature: Update student details
Background: User logged in to application
Given I should load all of the routes required for tests
Scenario: Update student details
When I am logged in as the student user
And I click on "Student" subtab
And I should see details displayed
Step definition:
import { Then, When, And } from "cypress-cucumber-preprocessor/steps";
before(() => {
Then('I should load all of the routes required for tests', () => {
cy.server();
cy.route({
method: 'POST',
url: '**student/details.php?viewDetails=project&stdCount=1&sectionID=1&openHash=5fc8329a76e73&ajaxCall=true**',
delay: 2000
}).as('getStudentTabDetails');
})
})
Then('I am logged in as the student user', () => {
cy.get('[name=loginUsername]').type("Student1");
cy.get('[name=loginPassword]').type("somePassword1", { sensitive: true });
cy.contains('Login').click();
})
Then('I click on {string} subtab', (student) => {
cy.get('#main a').contains(student).click({force:true});
});
Then('I should see details displayed', () => {
cy.wait('#getStudentTabDetails', { timeout: 5000 });
});
Error:
CypressError
Timed out retrying: cy.wait() timed out waiting 5000ms for the 1st request to the route: getStudentTabDetails. No request ever occurred.
Cypress.minimatch is a tool that can be used for checking the route matchers.
By default Cypress uses minimatch to test glob patterns against request URLs.
If you’re struggling with writing the correct pattern you can iterate much faster by testing directly in your Developer Tools console.
The two routes you show in the question actually pass the minimatch test.
const url = 'http://example/student/details.php?viewDetails=project&stdCount=1&sectionID=1&openHash=5fc8329a76e73&ajaxCall=true';
const pattern1 = '**/student/details.php?viewDetails=project&stdCount=1&sectionID=1&openHash=**';
console.log( Cypress.minimatch(url, pattern1) ); // true
const pattern2 = '**/student/details.php?viewDetails=project&stdCount=1&sectionID=1&openHash=**&ajaxCall=true**';
console.log( Cypress.minimatch(url, pattern2) ); // true
Here is a Cypress fiddle that shows how to use the new intercept method to handle query parameters.
/// <reference types="#cypress/fiddle" />
const test = {
html: `
<p class="text-lg"></p>
<script>
setTimeout(() => {
const url = 'http://example/student/details.php?viewDetails=project&stdCount=1&sectionID=1&openHash=5fc8329a76e73&ajaxCall=true';
window.fetch(url, { method: 'POST'});
}, 1000);
</script>
`,
test: `
cy.intercept({
method: 'POST',
url: '/student/details.php',
query: {
viewDetails: 'project', // whatever query parts you care about
stdCount: '1',
sectionID: '1'
}
}, {}) // Added an empty stub here, as my url does not actually exist
.as('getStudentTabDetails');
cy.wait('#getStudentTabDetails')
`
}
it('', () => {
cy.runExample(test)
});
The POST is made with native fetch(), which would not be captured in the old cy.route() method without using a polyfill.

Cypress: Page doesn't load within the second 'it' block for the click action

It works fine for the same click event if I've coded within the single 'it' block as below.
Working code:
describe('Test Suite', () => {
it('Test case 1', () => {
//Test 1
//Test 2
})
})
Not working:
describe('Test Suite', () => {
it('Test case 1', () => {
//Test 1
})
it('Test case 2', () => {
//Test 2
})
})
Below is my code snippet, First 'it' block works fine after login method executes. Then second it blocks just clicking the right element but the page never loads.
P.S. If I written the code under the single 'it' block, Page loads and works fine.
describe('Fund Manager Suite', () => {
//Checking Fund Manager page loading
before(() => {
cy.visit('xxxxxxxxxxxxx')
cy.login('xxxxx', 'xxxxx')
})
it('fund manager navigation works', () => {
cy.location('pathname').should('equal', '/xxxxx')
cy.get('#appSwitcher').click()
cy.get('#appSwitcher > .dropdown > .dropdown-menu > :nth-child(2) > a').click()
cy.location('pathname').should('equal', '/xxxxx')
cy.get('.k-grid-table').find('tr').should('have.length', 5)
})
it('fund detail works', () => {
cy.get('.product > :nth-child(2)').click()
cy.location('pathname').should('equal', '/xxxxx')
// Fund Detail - Search
cy.get('#s2id_autogen31').type('Rach')
cy.get('#select2-result-label-32').click()
cy.get('#searchSubmit').click()
cy.get('#DataTables_Table_0').find('tr').should('have.length', 10)
})
})
Execution Screen shot
Code snippet screen shot
You have to preserve your cookies in beforeEach() to make sure that you stay logged in, in all it() blocks. You can read more in cypress docs.
describe('Dashboard', () => {
before(() => {
// log in only once before any of the tests run.
// your app will likely set some sort of session cookie.
// you'll need to know the name of the cookie(s), which you can find
// in your Resources -> Cookies panel in the Chrome Dev Tools.
cy.login()
})
beforeEach(() => {
// before each test, we can automatically preserve the
// 'session_id' and 'remember_token' cookies. this means they
// will not be cleared before the NEXT test starts.
//
// the name of your cookies will likely be different
// this is an example
Cypress.Cookies.preserveOnce('session_id', 'remember_token')
})
it('displays stats', () => {
// ...
})
it('can do something', () => {
// ...
})
it('opens a modal', () => {
// ...
})
})
I Have seen this kind of behavior, when the first it case start and doesn`t finish some xhr request in the site - and in result cypress continues the process during the start of the second it case. The best solution for clean slate for each case I had found is to separate every case in different file
Update:
Able to resolve this issue by storing the session_id.
Cypress.Cookies.defaults({
preserve: "session_id"
})

Categories

Resources