How to debug this Testcafe case? - javascript

I've written 12 tests in total so far for this project and there is one error that is occurring in different places depending on the tests composition.
My question is about how to debug this issue.
I'll share the error and the test sample in hope that someone else had a similar problem and has an idea on how to approach it.
The Uncaught TypeError: Cannot read property 'type' of undefined is the error in question, and there is no reference to the where it occurred.
From the tests perspective, the next action was supposed to be clicking a button and getting a popup for creating a new product.
The application works correctly and without problems, it's just the e2e tests that report the problem.
The reported test in question works in isolation.
Excluding this test, the error manifests on another test.
At the end of this post, you'll be able to see the error thrown when this test is skipped.
fixture('Select a product from the list:')
.page('http://localhost:3000/products');
// #TODO Fix e2e test
test
.before(generateProducts(page, 1))
('clicking the "Close detail" button should return us to the products page.', async t => {
const productsListItem = await page.listContainer.child(0);
await t
.click(productsListItem)
.click(page.closeDetail)
.expect(page.productsPageTitle.innerText).eql('PRODUCTS')
})
.after(removeGeneratedProducts(detailedProductPage, 1));
test
.before(generateProducts(page, 2))
('selecting another product, while the previous is still opened, should refresh the preview with the new selection.', async(t) => {
const productListItems = await page.listContainer.find('li');
const productsListItem0 = await productListItems.nth(0);
const productsListItem0Title = await productsListItem0.find('[data-test-id="name"]').innerText;
const productsListItem1 = await productListItems.nth(1);
const productsListItem1Title = await productsListItem1.find('[data-test-id="name"]').innerText;
await t
.click(productsListItem0)
.expect(page.productTitle.textContent).eql(productsListItem0Title || 'Missing product\'s name')
.click(productsListItem1)
.expect(page.productTitle.textContent).eql(productsListItem1Title || 'Missing product\'s name')
})
.after(removeGeneratedProducts(detailedProductPage, 2));
fixture('Field state updating when switching between products with an open Quick Edit view')
.page('http://localhost:3000/products');
test
.before(async t => {
await t
.click(page.showAddProductFormButton)
.typeText(page.nameField, `${chance.name()} ${Math.floor(Math.random() * 100000) + 1}`)
.click(page.createNewProductButton)
.click(page.showAddProductFormButton)
.click(page.createNewProductButton);
})
('Products quick edit navigation should update the view, and not inherit the values of the previous product', async(t) => {
const productListItems = await page.listContainer.find('li');
const productsListItem0 = await productListItems.nth(0);
const productsListItem1 = await productListItems.nth(1);
await t
.click(productsListItem0)
.expect(page.productTitle.textContent).eql('Missing product\'s name')
.click(productsListItem1)
.click(productsListItem0)
.click(productsListItem1)
.click(productsListItem0)
.expect(page.productTitle.textContent).eql('Missing product\'s name')
.click(productsListItem0)
})
.after(removeGeneratedProducts(detailedProductPage, 2));
Don't expect results when running the code. I've used this feature to nicely import the code, nothing more.
The same error on a different test when the original test is skipped.

In the current product version (0.23.0), we've introduced the Stop Test Run After the First Test Fail option. You can now configure TestCafe to stop the entire test run after the first test failure. This saves your time when you fix problems with your tests one by one.
Using the mentioned --debug-on-fail option, you can specify whether to automatically enter the debug mode when a test fails. If this option is enabled, TestCafe pauses the test when it fails. This allows you to view the tested page and determine the cause of the failure.
In addition, you can use the --debug-mode option. In this mode, test execution is paused before the first action or assertion allowing you to invoke the developer tools and debug.
See also: TestCafe Debugging

Related

How to find the right testId - Testcafe Error E24

Creating tests using testcafe, this is pre-existing code written:
When(/^I click on username button$/, async () => {
await get TestCafeController().click(stepsHelper.getElementByTestId('user'));
});
getElementByTestId(dataTestId) returns:
Selector(`[data-testid="${dataTestId}"]`).with({ boundTestRun: getTestCafeController() });
'user' is the wrong test id. I'm pretty new to testing so how would I find the correct data-testid? Here's an image of the error I'm receiving:
TestCafe Error Code: E24
I tried different data-testids and looked through the code I was testing. The app I'm testing has two different modes and I'm trying to find the id of the user button. One mode works with 'user' but the mode I'm writing a test for doesn't work with 'user'.

Cypress error when testing nested iframes in headless mode - race condition

I am testing a web app and the test runs reliably in headed mode (cypress open) but has errors in headless mode (cypress run), so it's likely a race condition that I cannot resolve. The error message is:
[36819:0223/163815.745047:ERROR:system_services.cc(34)] SetApplicationIsDaemon: Error Domain=NSOSStatusErrorDomain Code=-50 "paramErr: error in user parameter list" (-50)
This error is mentioned again when Cypress creates a video of the incident:
- Started processing: Compressing to 32 CRF
2022-02-23 17:00:19.700 Cypress Helper[37571:416134] In -[NSApplication(NSQuietSafeQuit) _updateCanQuitQuietlyAndSafely], _LSSetApplicationInformationItem(NSCanQuitQuietlyAndSafely) returned error -50
- Finished processing: /Users/malte.wirz/Documents/iframes-cypress-issue/cypress/videos/iframe-github.js.mp4 (3 seconds)
I created a demo repository here. To reproduce, clone it, run yarn to install, and yarn cypress:run. The test does pass, but with the error mentioned above.
I assume that the error stems from accessing the nested iframes and I tested 5 different approaches so far, but to no avail. I especially made sure that the function getIframeBody waits until each iframe and the requested element is ready. The error also creates a video, but you can only see the successful run, the error message is not visible there.
Any help on how to debug this further is much appreciated.
describe('Testing Iframe within Iframes', () => {
it('Visits the iframe website and accesses the iframe within the iframe', () => {
const getIframeBody = (iframeSelector, elementSelectorInIframe) => {
return cy
.get(iframeSelector)
.its('0.contentDocument.body', {timeout: 30000})
.should((body) => {
expect(Cypress.$(body).has(elementSelectorInIframe).length).gt(0)
})
.then(cy.wrap)
}
// Visiting the page index.html and getting iframe A
cy.visit('index.html').contains('XHR in iframe')
getIframeBody('iframe[data-cy="bankid"]', 'iframe[src="https://tools.bankid.no/bankid-test/auth"]').as('iframeA')
cy.get('#iframeA').within(() => {
getIframeBody('iframe[src="https://tools.bankid.no/bankid-test/auth"]', 'iframe[src^="https://csfe.bankid.no/CentralServerFEJS"]').as('iframeB')
cy.get('#iframeB').within(() => {
getIframeBody('iframe[src^="https://csfe.bankid.no/CentralServerFEJS"]', 'input[type="tel"]').as('iframeC')
// Now we are in the right place and it finds the correct input element.
// However, normal cypress command .type() fails and we have to use library cypress-real-events,
// which provides an event firing system that works literally like in puppeteer
cy.get('#iframeC').find('input[type="tel"]').should('be.visible').realType('12345678912')
// But for the button below, this library now doesn't help anymore:
// "Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'."
// This was solved by using {scrollBehavior:false}.
cy.get('#iframeC').find('button[type="submit"]').should('be.visible').first().realClick({scrollBehavior:false})
})
})
})
})
I got some feedback that the above "ERROR:system_services.cc(34)" is not critical and does not cause flaky or unsuccessful tests, therefore there are no action points.

How to ignore the "ResizeObserver loop limit exceeded" in TestCafe

I'm currently using TestCafe for some e2e tests. I've run into the following error
1) - Error in Role initializer -
A JavaScript error occurred on "http://localhost:3000/".
Repeat test actions in the browser and check the console for errors.
If you see this error, it means that the tested website caused it. You can fix it or disable tracking JavaScript errors in TestCafe. To do the latter, enable the "--skip-js-errors" option.
If this error does not occur, please write a new issue at:
"https://github.com/DevExpress/testcafe/issues/new?template=bug-report.md".
JavaScript error details:
ResizeObserver loop limit exceeded
No stack trace available
A bit of research suggests that the ResizeObserver loop limit exceeded issue is a benign error.
However, it causes my test to fail. Is there any way I can ignore this specific error without using the --skip-js-errors flag, as I would prefer to not ignore all JavaScript errors because of this one issue
As far as I understand, this error occurs when ResizeObserver cannot deliver all observations within a single animation frame. A person who is the author of the ResizeObserver specification assures that it can be safely ignored: ResizeObserver loop limit exceeded
Chrome and Firefox don't display it by default. You can only catch it when you set an explicit onerror handler:
window.onerror = e => console.log(e);
You can see that this error is reproduced on the Google Sign In page without TestCafe. I added an onerror handler to the page and got ResizeObserver loop completed with undelivered notifications. in Firefox and ResizeObserver loop limit exceeded in Chrome.
As a workaround, you can specify the --skip-js-errors flag when starting TestCafe. I admit that it's not the best approach since you will suppress all Javascript errors on a tested page.
A more reliable way is to add a global window error handler explicitly in your tests via client scripts:
import { Selector, t } from 'testcafe';
// Constants
const gmailEmailInput = Selector("#identifierId");
const gmailNextButton = Selector(".CwaK9");
const gmailPasswordInput = Selector("input[type='password']");
const explicitErrorHandler = () => {
window.addEventListener('error', e => {
if(e.message === 'ResizeObserver loop completed with undelivered notifications.' ||
e.message === 'ResizeObserver loop limit exceeded') {
e.stopImmediatePropagation();
}
})
}
fixture("Gmail login test")
.clientScripts({ content: `(${explicitErrorHandler.toString()})()` });
test("Not trigger JS error when logging in to Gmail", async testController => {
await testController
.navigateTo("https://mail.google.com")
.typeText(gmailEmailInput, "someuser#gmail.com")
.click(gmailNextButton)
.typeText(gmailPasswordInput, "password")
});
I copypasted the workaround from here.

The following error originated from your application code, not from Cypress

i tried to test this simple code
type Url = string
it('loads examples', () => {
const url: Url = 'https://www.ebay.com/'
cy.visit(url)
cy.get('input[type="text"]').type('book')
cy.get('#gh-btn').click();
})
then I faced this error
how can I solve it
Try adding this in support/index.js:
import './commands'
Cypress.on('uncaught:exception', (err, runnable) => {
// returning false here prevents Cypress from failing the test
return false
})
This should avoid the uncaught:exception in the click() method.
The accepted answer will cause Cypress to ignore all uncaught exceptions in the application. Generally, when these come up it means you found a bug in your app and should fix it.
Binding to the global Cypress object causes the event to stay bound for your entire test run. Usually, this isn't what you want.
If you actually need to ignore the exceptions though, you should be binding the event on the cy object so it's only persisted for the single test it's used in.
it('my test', () => {
cy.once('uncaught:exception', () => false);
// action that causes exception
cy.get('body').click();
});
I got Same Issue like this
Cypress Error
The following error originated from your application code,
not from Cypress. >
Cannot read properties of null (reading 'textContent')
When Cypress detects uncaught errors originating from
your application it will automatically fail the current test.
This behavior is configurable, and you can choose to turn this off by
listening to the uncaught:exception event.Learn more
No Need to worry about this.
Just paste this code to your index.js file :)
import './commands'
Cypress.on('uncaught:exception', (err, runnable) => {
// returning false here prevents Cypress from
// failing the test
return false
})
Actually, if you click in the Learn more link that comes with the error, you'll get everything you need.
https://docs.cypress.io/guides/references/error-messages#Uncaught-exceptions-from-your-application
Quoting others:
won't this answer ignore all errors thrown by the application?
The accepted answer will cause Cypress to ignore all uncaught exceptions
That is true.
Also, #DJSDev did not work for me when using Cypress v10.0.3.
The aforementioned link provides a working alternative:
it('is doing something very important', (done) => {
// this event will automatically be unbound when this
// test ends because it's attached to 'cy'
cy.on('uncaught:exception', (err, runnable) => {
expect(err.message).to.include('something about the error')
// using mocha's async done callback to finish
// this test so we prove that an uncaught exception
// was thrown
done()
// return false to prevent the error from
// failing this test
return false
})
// assume this causes an error
cy.get('button').click()
})

Is it bad to show errors in Browser console when API call fails?

I have the following svelte code to fetch the random number and show on UI:
<script>
let promise = getRandomNumber();
async function getRandomNumber() {
const res = await fetch(`tutorial/random-number`);
const text = await res.text();
if (res.ok) {
return text;
} else {
throw new Error(text);
}
}
function handleClick() {
promise = getRandomNumber();
}
</script>
<button on:click={handleClick}>
generate random number
</button>
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
I took this code from : https://svelte.dev/examples#await-blocks
Api call can fail sometimes and show error in UI as :
Failed to generate random number. Please try again
While it does, it also prints the status code of API in console as :
Now, I am wondering is it a bad idea to show such kind of errors in UI? If so, how can I avoid showing these errors? This is something that is done by svelte I think. If we should avoid any kind of errors in console, what is the best way to write this part of code so that I could use svelte await also.
This type of error is consoled by the browser itself, so you will not be able to remove it.
You must check out for the cause because of which this error occurs.
And, Yes you should avoid showing errors and messages in the console. you should show these error in UI.

Categories

Resources