Playwright hook / callback / try-catch to handle the overall test timeout - timeout

When the timeout specified as below in playwright.config.ts expires, Playwright simply blows away the browser. How can I catch this timeout expiry in my Playwright test script, and handle it gracefully? I would like to log the timeout and exit the test gracefully.
Thanks,
Sanjoy
// playwright.config.ts
import type { PlaywrightTestConfig } from '#playwright/test';
const config: PlaywrightTestConfig = {
timeout: 60000, // Timeout is shared between all tests.
I would like a hook / callback that can log the timeout and close the browser gracefully.

Related

Playwright: Saving session storage

I'm very new to Playwright. I'm trying to follow this https://playwright.dev/docs/auth#reuse-signed-in-state so I can login and then save the session for further tests.
My steps work fine in a test but once I've moved them to global-setup.ts I get a timeout:
import { chromium, FullConfig } from '#playwright/test'
async function globalSetup(config: FullConfig) {
const browser = await chromium.launch()
const page = await browser.newPage()
await page.goto('MYDOMAIN/login');
await page.locator("a[testid='googleSignIn']").click()
await page.locator("input[type='email']").fill('MYEMAIL')
await page.locator(
"button[class='VfPpkd-LgbsSe VfPpkd-LgbsSe-OWXEXe-k8QpJ VfPpkd-LgbsSe-OWXEXe-dgl2Hf nCP5yc AjY5Oe DuMIQc LQeN7 qIypjc TrZEUc lw1w4b']",
).click()
await page.locator("input[type='password']").fill('MYPASSWORD')
await page.locator(
"button[class='VfPpkd-LgbsSe VfPpkd-LgbsSe-OWXEXe-k8QpJ VfPpkd-LgbsSe-OWXEXe-dgl2Hf nCP5yc AjY5Oe DuMIQc LQeN7 qIypjc TrZEUc lw1w4b']",
).click()
// Save signed-in state to 'storageState.json'.
await page.context().storageState({ path: 'storageState.json' })
await browser.close()
}
export default globalSetup
The above steps log me in fine in a test but now I've set my config file to use the saved session storage:
storageState: 'storageState.json',
When I run a test I don't see a browser appear it just waits a minute and then says:
locator.click: Timeout 30000ms exceeded.
=========================== logs =========================== waiting for selector "button[class='VfPpkd-LgbsSe VfPpkd-LgbsSe-OWXEXe-k8QpJ
VfPpkd-LgbsSe-OWXEXe-dgl2Hf nCP5yc AjY5Oe DuMIQc LQeN7 qIypjc TrZEUc
lw1w4b']"
at ../../global-setup.ts:15
13 | await page.locator( 14 | "button[class='VfPpkd-LgbsSe
VfPpkd-LgbsSe-OWXEXe-k8QpJ VfPpkd-LgbsSe-OWXEXe-dgl2Hf nCP5yc AjY5Oe
DuMIQc LQeN7 qIypjc TrZEUc lw1w4b']",
15 | ).click()
| ^
The time out is the step just before I enter my password.
I'm running the tests with this command:
yarn playwright test login-page-tests --headed
Am I doing something wrong?
I wouldn't count on these google login class names. Did you try running something like:
await page.locator('text="Next"').click()

wdio / Appium - " TypeError: $(...).waitForDisplayed is not a function" in my test

I am trying to learn to automate End2end testing a React-native mobile App using wdio and appium.
The target component I am trying to click in this problem is this:
Component screen shot
I got an error of TypeError: $(...).waitForDisplayed is not a function" in my current test project. While I got "elements not found" when I'll do assync mode.
I can verify that the IDs are visible in Appium Element Inspector
ScreenShot here
Below are my codes (#1 & #2) Either way, I got an error. I really need to understand why I got this errors.
#1
describe('Test Unit - Assync Mode', () => {
it('Client must be able to login in the app. ', async () => {
// pay attention to `async` keyword
const el = await $('~pressSkip') // note `await` keyword
await el.click()
await browser.pause(500)
})
})
Error Message
#2
beforeEach(() => {
$('~pressSkip').waitForDisplayed({ timeout: 20000 })
})
describe('My Simple test', () => {
it('Client must be able to login the app', () => {
// Click Skip button id: "pressSkip"
$('~pressSkip').click();
// Enter Login
// Email id: "loginEmail"
// Password id: "loginPwd"
// Click Login Button id:
});
});
=============
Wdio.conf.js
=============
const { join } = require('path');
exports.config = {
//
// ====================
// Runner Configuration
// ====================
//
// WebdriverIO allows it to run your tests in arbitrary locations (e.g. locally or
// on a remote machine).
runner: 'local',
//
// ==================
// Specify Test Files
// ==================
specs: [
'./test/specs/**/*.js'],
// ============
// Capabilities
// ============
//
capabilities: [{
// http://appium.io/docs/en/writing-running-appium/caps/
// This is `appium:` for all Appium Capabilities which can be found here
'appium:platformName': 'Android',
'appium:deviceName': 'emulator-5554',
'appium:platformVersion': '8.1.0',
'appium:newCommandTimeout': '60',
'appium:app': join(process.cwd(), '/android/app/build/outputs/apk/debug/app-debug.apk'),
}],
//
// If you only want to run your tests until a specific amount of tests have failed use
// bail (default is 0 - don't bail, run all tests).
bail: 0,
//
// Set a base URL in order to shorten url command calls. If your `url` parameter starts
// with `/`, the base url gets prepended, not including the path portion of your baseUrl.
// If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
// gets prepended directly.
baseUrl: 'http://localhost:/wd/hub',
//
// Default timeout for all waitFor* commands.
waitforTimeout: 10000,
//
// Default timeout in milliseconds for request
// if browser driver or grid doesn't send response
connectionRetryTimeout: 120000,
//
// Default request retries count
connectionRetryCount: 3,
//
// Test runner services
// Services take over a specific job you don't want to take care of. They enhance
// your test setup with almost no effort. Unlike plugins, they don't add new
// commands. Instead, they hook themselves up into the test process.
services: [['appium',{
// This will use the globally installed version of Appium
command: 'appium',
args: {
basePath: "/wd/hub",
// This is needed to tell Appium that we can execute local ADB commands
// and to automatically download the latest version of ChromeDriver
relaxedSecurity: true,}
}]],
port: 4723,
hostname: "localhost",
// Make sure you have the wdio adapter package for the specific framework installed
// before running any tests.
framework: 'jasmine',
//
// Test reporter for stdout.
// The only one supported by default is 'dot'
// see also: https://webdriver.io/docs/dot-reporter
reporters: ['spec'],
//
// Options to be passed to Jasmine.
jasmineOpts: {
// Jasmine default timeout
defaultTimeoutInterval: 60000,
//
// The Jasmine framework allows interception of each assertion in order to log the state of the application
// or website depending on the result. For example, it is pretty handy to take a screenshot every time
},
}
describe('Test Unit - Assync Mode', () => {
it('Client must be able to login in the app. ', async () => {
// pay attention to `async` keyword
await (await $('~pressSkip')).waitForDisplayed({ timeout: 20000 })
const el = await $('~pressSkip') // note `await` keyword
await el.click()
await browser.pause(500)
})
})
add await to the waitfordisplay also

Axios - ERR_EMPTY_RESPONSE on long lasting requests

I have a REST backend for executing Selenium UI test. Sending a GET request with test names executes them and returns the result. The problem is that running some of these tests takes a long time, often over 5 minutes or more.
When I try to run a lengthy set of tests, after about 2 minutes I get an error Failed to load resource: net::ERR_EMPTY_RESPONSE.
The server seems to be working correctly. When I tried to send the request from Insomnia, I get correct response even after more than 5 minutes of running.
My code for sending the GET request
handleRunTests = (tests) => {
const httpClient = axios.create();
httpClient.defaults.timeout = 60 * 60 * 1000; // one hour timeout for running tests
this.setState({
testsResults: {},
testsRunning: true
});
let url = `/api/runTests?tests=${tests}`;
httpClient.get(url)
.then(result => {... handle test results ...}
.catch(error => {
this.setState({
testsRunning: false,
error
});
})
};

Cypress visit and wait timeouts ignored

I created a test where I setup a route, try to visit a page which makes an API request to the route and then wait for the route response:
cy
.server()
.route('GET', '/api/testing')
.as('testing');
cy.visit('/index.html', { timeout: 60000 });
cy.wait('#testing', { timeout: 60000 });
This only waits for the Cypress global default responseTimeout of 30 seconds and then fails the API request.
Here's the error message logged by Cypress in the console:
Cypress errored attempting to make an http request to this url:
https://localhost:4200/api/testing
The error was:
ESOCKETTIMEDOUT
The stack trace was:
Error: ESOCKETTIMEDOUT
at ClientRequest. (…\node_modules\cypress\dist\Cypress\resources\app\packages\server\node_modules\request\request.js:778:19)
at Object.onceWrapper (events.js:314:30)
at emitNone (events.js:105:13)
at ClientRequest.emit (events.js:207:7)
at TLSSocket.emitTimeout (_http_client.js:722:34)
at Object.onceWrapper (events.js:314:30)
at emitNone (events.js:105:13)
at TLSSocket.emit (events.js:207:7)
at TLSSocket.Socket._onTimeout (net.js:402:8)
at ontimeout (timers.js:469:11)
at tryOnTimeout (timers.js:304:5)
at Timer.listOnTimeout (timers.js:264:5)
Adding a responseTimeout to the global config of Cypress will increase the timeout, but why isn't the timeout for either the visit or the wait occurring?
See the code example on this page commands - wait - Alias
// Wait for the route aliased as 'getAccount' to respond
// without changing or stubbing its response
cy.server()
cy.route('/accounts/*').as('getAccount')
cy.visit('/accounts/123')
cy.wait('#getAccount').then((xhr) => {
// we can now access the low level xhr
// that contains the request body,
// response body, status, etc
})
I would add the then((xhr) => to your code and see what response is coming through.
Logic says that if a bogus route waits the full timeout, but a 'failed legitimate route' does not, then a response with failure code is being sent back from the server within the timeout period.
The block of code in request.js where the error comes from has an interesting comment.
self.req.on('socket', function(socket) {
var setReqTimeout = function() {
// This timeout sets the amount of time to wait *between* bytes sent
// from the server once connected.
//
// In particular, it's useful for erroring if the server fails to send
// data halfway through streaming a response.
self.req.setTimeout(timeout, function () {
if (self.req) {
self.abort()
var e = new Error('ESOCKETTIMEDOUT') <-- LINE 778 REFERENCED IN MESSAGE
e.code = 'ESOCKETTIMEDOUT'
e.connect = false
self.emit('error', e)
}
})
}
This may be a condition you want to test for (i.e connection broken mid-response).
Unfortunately, there seems to be no syntax cy.wait().catch(), see Commands-Are-Not-Promises
You cannot add a .catch error handler to a failed command.
You may want to try stubbing the route instead of setting the breakpoint on the server, but I'm not sure what form the fake response should take. (Ref route with stubbing)
.vist() and .wait() didn't work for me, error logs on cypress suggested using .request() instead which works fine.
cy.server();
cy.request('/api/path').then((xhr) => {
console.log(xhr.body)
})

How to increase the adapter procedure timeout value in Worklight?

How can I increase the timeout value of a Worklight adapter procedure? My app crashes and I see the following in the exception details:
"response [/apps/services/api/index/common/query] success: /-secure-
{"responseID":"24","errors":["Invocation of procedure 'getFTTitle' has
timed out after 30
sec."],"isSuccessful":false,"warnings":[],"info":[]}/ "
There are several places in Worklight where a timeout value can be specified:
CLIENT ----> WORKLIGHT SERVER -- (adapter) --> BACKEND
You can increase the adapter procedure timeout (Worklight Server --> Backend) as follows:
<procedure name="nameHere" requestTimeoutInSeconds="valueHere"/>
I don't know what is your specific use case, so be sure to also increase the client-side timeout. Have them match each other.
WL.Client.invokeProcedure(invocationData,{
onSuccess : getDataSuccess,
onFailure : getDataFailure,
timeout : valueHere
});
Also note that if you need to increase your timeout to a whole minute, consider that something may not be right here...
var wlInitOptions =
{
// # Worklight server connection timeout
timeout: 60000,
...
}

Resources