Detox: Testing a React-Native spinner with a stop button - react-native

Was wondering if anyone has had a similar issue.
In the app I'm working with, we have a spinner showing downloading content with a stop button in the middle. When the user taps the spinner/stop button, the download is meant to cancel. For reference the spinner/stop button looks like this on iOS:
I'm trying to write an e2e test for this functionality using Detox. It doesn't work using automatic synchronisation as the animation (and the download) keeps the thread running. I've tried using device.disableSynchronization() but I haven't had any success.
Here's my e2e test for reference:
it('should start and then cancel a download from the <My Learning> screen', async() => {
// setup
await device.reloadReactNative()
await expect(element(by.id('feed_screen'))).toBeVisible()
await element(by.id('LearningPlan_Tab')).tap()
await expect(element(by.id('learning-plan-screen'))).toBeVisible()
// Tap the download icon, it will turn into a spinner
await element(by.id('offline_download_c2a')).atIndex(1).tap()
// Alert box appears with Cancel/Download options
await expect(element(by.label('Download')).atIndex(1)).toBeVisible()
await element(by.label('Download')).atIndex(1).tap()
// Ideally this would work, but it doesn't (the above alert box doesn't dismiss properly)
await device.disableSynchronization()
await waitFor(element(by.id('download_spinner_c2a')).atIndex(0)).toBeVisible().withTimeout(5000)
await element(by.id('download_spinner_c2a')).atIndex(0).tap()
await device.enableSynchronization()
await element(by.label('Cancel download')).tap()
await expect(element(by.id('offline_download_c2a')).atIndex(1)).toBeVisible()
})
When this test runs the app still seems to wait for the download to finish. Does anyone know any suggestions on the best way to test this, or if it's even possible?

I've found a way to make it work, though it seems quite flaky:
it('should start and then cancel a download from the <My Learning> screen', async () => {
//...
await device.disableSynchronization()
// This timeout seems to help
await waitFor(element(by.id('download_spinner_c2a')).atIndex(0)).toBeVisible().withTimeout(10000)
await element(by.id('download_spinner_c2a')).atIndex(0).tap()
await device.enableSynchronization()
await element(by.label('Cancel download')).tap()
await expect(element(by.id('offline_download_c2a')).atIndex(1)).toBeVisible()
})

Related

Playwright test works fine localy, but fails in pipeline

I am trying to run this code:
test('should login', async ({ page }) => {
await page.goto(localhost);
await page.fill('[name=username]', 'username');
await page.fill('[name=password]', 'password');
await page.click('[name=login]');
await page.waitForURL(`${localhost}/main`);
const currentUrl = await page.url();
expect(currentUrl).toBe(`${localhost}/main`);
});
When I run it with npx playwright test localy, the test passes; but, when run in CI/CD, it fails:
Timeout of 180000ms exceeded.
page.waitForURL: Navigation failed because page was closed!
=========================== logs ===========================
waiting for navigation to "http://localhost:3000/main" until "load"
============================================================
Any idea what causes this problem?
I would try logging all network requests to see what's going on there:
// Log and continue all network requests
page.route('**', (route, request) => {
console.log(request.url());
route.continue();
});
If it never gets beyond the goto(), perhaps try using the new playwright request fixture to see if it can even reach http://localhost:3000/main.
await page.request.get("http://localhost:3000/main", { ignoreHTTPSErrors: true });

How do I deal with a page loading in a secondary browser tab when I run Protractor tests headless (Chrome)?

When this code clicks a “Print”-icon, a PDF-file will be generated and displayed in a new browser-tab. I want to switch to this tab, wait until the PDF has finished loading there, check a part of the URL and then close that secondary tab.
it( "should open document as PDF-file in new browser-tab", async () => {
const mUrl = "TherapyReportForm/Export";
await mTherapyReportView.btnPrintform.click();
await browser.getAllWindowHandles().then(async (handles) => {
//if there is a secondary browser-tab open...
if (handles.length > 1) {
//...click on it
await browser.driver.switchTo().window(handles[1]);
}
});
//confirm that the url of the secondary tab matches the print-url pattern
await browser.sleep( 18000 );
expect( await browser.getCurrentUrl() ).toContain( mUrl );
await browser.getAllWindowHandles().then( async (handles) => {
//if there are multiple browser-tabs open
if (handles.length > 1) {
//close the secondary and move back to first
await browser.driver.close();
await browser.driver.switchTo().window( handles[0] );
}
} );
} );
The test above works reliably, unless I run it in chromes headless-mode, then the test-run breaks at line
expect(await browser.getCurrentUrl()).toContain(mUrl);
console output
The console output proves that it switches to the secondary tab, but apparently never tries to load the url. Since it fails to close this secondary tab the entire suite will break at that point.
What am I doing wrong?
Here is a thing... downloading functionality is not available in headless chrome. That's for sure. What I'm going to talk about below, I'm a little bit uncertain if that's the case
There is no such thing as 'open' pdf file in browser. The reason is that behind scene the browser actually downloads it (maybe temporarily). This is why you'll never be able to do that in headless
But that's rather a shot in the dark

Is there a way to keep 'select' options open for screenshots?

I'm trying to take screenshots of a site and need to keep a 'select' menu-open so that I can capture its contents. It always closes before taking the screenshot.
I've tried taking a screenshot after clicking on the menu
test('SelectOptionsScreenshot', async t => {
await faveDogs.load(t)
await t
.click(faveDogs.dogSelect)
.takeScreenshot()
I've tried it by telling it to look for 'options' with no specific text
test('SelectOptionsScreenshot', async t => {
await faveDogs.load(t)
await t
.click(faveDogs.dogSelect)
.click(faveDogs.dogSelect.find('option')
.takeScreenshot()
I've tried having it hover over an option
test('SelectOptionsScreenshot', async t => {
await faveDogs.load(t)
await t
.click(faveDogs.dogSelect)
.hover(faveDogs.dogSelect.find('option').withText('German Shepherd')
.takeScreenshot()
It looks like you faced an issue in the current product version. I've reproduced this behavior and we are going to look into it in the context of this thread created based on your information: https://github.com/DevExpress/testcafe/issues/4101.

How to close the safari pop up dialogue when running automate script with nightwatch on BrowserStack?

I use Browserstack to do the E2E testing, now I met a problem when I try to run the mobile automate script in safari on Browserstack, there will have a pop-up dialogue show when I click a button which will result in opening a new tab, the dialogue show message like this: 'this site is attempting to open a popup window', I must close it and the script can continue executing.
Now the problem is:
1. When I click the button which will trigger this pop-up dialogue, there will always show an exception in the log: 'Error while running .clickElement() protocol action: Appium error: An unknown server-side error occurred while processing the command. Original error: Did not get any response after 20s'.
2. I can use the XPath to locate the button on the pop-up dialogue and click it to close the dialogue, but it takes serval minutes, is there another way to do this operation more efficient?
const { client } = require('nightwatch-api')
const { Given, Then, When} = require('cucumber')
Given('open mobile 163 news', async function () {
await client.url('https://3g.163.com/news/article/EJN99AOF000189FH.html?clickfrom=index2018_news_newslist#offset=0')
})
When('choose share by QQ', async function () {
await client.waitForElementVisible('.sharelogo')
await client.click('.sharelogo')
})
Then('the popup should show', async function () {
await client.waitForElementVisible('.qzone')
await client.click('.qzone')
await client.setContext('NATIVE_APP')
await client.source(function(res){
console.log(res.value)
})
await client.useXpath()
await client.click('//*[#name="Allow"]')
await client.contexts(function(result) {
client.setContext(result.value[result.value.length - 1])
client.useCss()
})
})
Have you tried adding the capability 'nativeWebTap' and setting it to the value 'true' in the test scripts?

Detox tests are breaking

This is regarding detox e2e tests.
I am running my tests, each under an it('xx', async => { await...});
The tests are scripted in such a way that 1st test would log in, 2nd test would do something on homepage, 3 rd test would navigate from homepage to other pages and so on.
The issue here is, as soon as my first test executes, the app is getting logged out and all the consecutive tests are failing.
But when I include all steps(right from login to the desired functionality) in every test, the suite is working properly.
I would like to know why is this happening. Is there any connection with async function?
One of the gotchas for using Detox is that the sample test specification uses a beforeEach and there is a tendency to copy verbatim examples that we are given, some times missing out things that either need to be removed or should be added.
In this particular case in the beforeEach there is the call await device.reloadReactNative(); this command reloads the device as if you had pressed CMD+R (on iOS) or RR (on Android). This means that items that have been saved to state are lost and the application is pretty much returned to its initial state.
Check your code for the offending line, you can see it in example provided below. If you remove this line then it will stop reloading React Native on your device before each test.
example.spec.js
https://github.com/wix/Detox/blob/master/examples/demo-react-native/e2e/example.spec.js
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative(); // <- this is the problem
});
it('should have welcome screen', async () => {
await expect(element(by.id('welcome'))).toBeVisible();
});
it('should show hello screen after tap', async () => {
await element(by.id('hello_button')).tap();
await expect(element(by.text('Hello!!!'))).toBeVisible();
});
it('should show world screen after tap', async () => {
await element(by.id('world_button')).tap();
await expect(element(by.text('World!!!'))).toBeVisible();
});
});