Disable all existing AND future debugger statements? [duplicate] - google-chrome-devtools

I know there is a Never pause here, but it's not works for code like this
setInterval(function(){
eval('debugger;'+Math.random())
},1000)
If I can't find the setInterval, I can not disable the pause, it's very annoying.
Is there any flag or somehow to disable this ?
EDIT
I found this issues(DevTools: impossible to disable a breakpoint caused by "debugger" statement) relate to this problem, in the test code I found a flag --expose-debug-as debug, but how can I use this flag for headless,
chrome --expose-debug-as debug --headless --disable-gpu '<URL>' --repl
[0610/020053.677043:ERROR:headless_shell.cc(459)] Open multiple tabs is only supported when the remote debug port is set.

Well the only choice you really have is to inject code into the page that overrides eval and removes it.
(function () {
var _eval = window.eval;
window.eval = function (str) {
_eval(str.replace(/debugger;/,""));
};
}());
eval("debugger;alert('a');")

I done this by disable interval and timeout, some site use this to prevent others watching code.
I insert code before onload by using chrome headless
Start headless
chrome --headless --disable-gpu <URL> --remote-debugging-port=9222
Other shell session
yarn add chrome-remote-interface
test.es6
const CDP = require('chrome-remote-interface');
async function test() {
const protocol = await CDP({port: 9222});
// Extract the DevTools protocol domains we need and enable them.
// See API docs: https://chromedevtools.github.io/devtools-protocol/
const {Page, Runtime, Debugger, Log, Console} = protocol;
try {
await Promise.all([
Page.enable(),
Runtime.enable(),
Log.enable(),
Console.enable(),
Debugger.disable(),
]);
} catch (e) {
console.log('Failed', e)
return
}
Log.entryAdded(({entry: e}) =>
console.log(`${new Date(e.timestamp).toISOString()} ${e.source}:${e.level} ${e.text}`)
);
Console.messageAdded(({message: e}) =>
console.log(`${new Date().toISOString()} ${e.source}:${e.level} ${e.text}`)
)
Page.navigate({url: URL_HERE});
// Inject code,disable setInterval and setTimeout
Runtime.executionContextCreated(async ({context}) => {
console.log('executionContextCreated')
let result = await Runtime.evaluate({
expression: `
window._si=window.setInterval
window.setInterval=(...args)=>{
let id = 1//window._si.apply(window,args)
console.warn(\`setInterval:\${args}\`,)
return id
}
window._st=window.setTimeout
window.setTimeout=(...args)=>{
let id = 1//window._st.apply(window,args)
console.warn(\`setTimeout:\${args}\`,)
return id
}
;location.href
`,
contextId: context.id,
});
console.log('executionContextCreated', result)
});
// Wait for window.onload before doing stuff.
Page.loadEventFired(async () => {
// Debugger.setSkipAllPauses(true)
const js = `
console.log('Page load');
document.querySelector('title').textContent
`;
// Evaluate the JS expression in the page.
const result = await Runtime.evaluate({expression: js});
console.log('Title of page: ' + result.result.value);
protocol.close();
});
}
test()
After script, open 'localhost:9222' in chrome, inspect the page, the debugger not run now.

If you don't need setInterval for anything else, just type this in the console:
window.setTimeout = null

Related

is there a way to check if the PWA was launched through a file or not?

I'm using the file handle API to give my web app the optional capability to launch through double-clicking files in the file explorer.
Writing the code below, I expected if (!("files" in LaunchParams.prototype)) to check if a file was used to launch the app, but apparently, it checks if the feature is supported. OK, that makes sense.
After that, I thought the setConsumer callback would be called in any launch scenario, and files.length would be zero if the app was launched in other ways (like by typing the URL in the browser). But on those use cases, the callback was not called at all, and my init logic was never executed.
if (!("launchQueue" in window)) return textRecord.open('a welcome text');
if (!("files" in LaunchParams.prototype)) return textRecord.open('a welcome text');
launchQueue.setConsumer((launchParams) => {
if (launchParams.files.length <= 0) return textRecord.open('a welcome text');
const fileHandle = launchParams.files[0];
textRecord.open(fileHandle);
});
I've also followed the Launch Handler API article instructions and enabled the experimental API.
The new code confirms that "targetURL" in LaunchParams.prototype is true, but the setConsumer callback is not executed if the user accesses the web app through a standard browser tab.
function updateIfLaunchedByFile(textRecord) {
if (!("launchQueue" in window)) return;
if (!("files" in LaunchParams.prototype)) return;
console.log({
'"targetURL" in LaunchParams': "targetURL" in LaunchParams.prototype,
});
// this is always undefined
console.log({ "LaunchParams.targetURL": LaunchParams.targetURL });
// setConsumer does not trigger if the app is not launched by file, so it is not a good place to branch what to do in every launch situation
launchQueue.setConsumer((launchParams) => {
// this never run in a normal tab
console.log({ setConsumer: launchParams });
if (launchParams.files.length <= 0) return;
const fileHandle = launchParams.files[0];
textRecord.open(fileHandle);
});
}
This is the result...
Is there a universal way to check if the web app was launched through a file?
Check out the Launch Handler origin trial. It lets you determine the launch behavior exactly and lets your app detect how the launch happened. This API works well together with the File Handling API that you already use. You could, for example, check the LaunchParams.targetURL to see how the app was launched. Your feedback is very welcome.
Since I was not able to guarantee that the setConsumer callback was called in every situation (especially when the app is launched in a regular browser tab), I hacked it through setTimeout:
function wasFileLaunched() {
if (!("launchQueue" in window)) return;
if (!("files" in LaunchParams.prototype)) return;
return new Promise((resolve) => {
let invoked = false;
// setConsumer does not triggers if the app is not launched by file, so it is not a good place to branch what to do in every launch situation
launchQueue.setConsumer((launchParams) => {
invoked = true;
if (launchParams.files.length <= 0) return resolve();
const fileHandle = launchParams.files[0];
resolve(fileHandle);
});
setTimeout(() => {
console.log({ "setTimeout invoked =": invoked });
if (!invoked) resolve();
}, 10);
});
}

Protractor : In a particular page, none of the protractor actions are working

My protractor script is working fine until a page where reveal.js package is used. I am not sure if that is the reason it causes the scripts to fail, but otherwise the code base is same as the other pages where my scripts works fine.
Note: I tried most of the protractor actions (click, highlight, waitForElement, toContain, etc), none of them worked. I could only click the links by inserting jQuery in my script.
CODE:
let HighlightElement = function (el) {
return browser.executeScript("arguments[0].setAttribute('style', arguments[1]);", el.getWebElement(), "color: Red; border: 1px solid red;").
then(function (resp) {
browser.sleep(2000);
return el;
}, function (err) { });
}
let waitUntilElementPresent = function (visibilityOfObject, maxWaitTime) {
var EC = protractor.ExpectedConditions;
browser.manage().timeouts().implicitlyWait(2);
browser.wait(function () {
browser.manage().timeouts().implicitlyWait(3);
return visibilityOfObject.isDisplayed()
.then(
function (isDisplayed) {
browser.wait(EC.visibilityOf(visibilityOfObject), maxWaitTime, "Element taking more time to load");
browser.manage().timeouts().implicitlyWait(3);
return isDisplayed;
},
function (error) {
return false;
});
}, 100000);
}
ACTUAL CODE:
var homepage = new homePageObj();
utilities.waitUntilElementPresent(homepage.waitScreenText); //here the script is failing. It is just a simple script and it used to work in other pages but it doesn’t work only in some of the pages
utilities.HighlightElement(homepage.waitScreenText);
utilities.HighlightElement(homepage.startButton);
homepage.startButton.click();
Error:
Failed: Wait timed out after 120062ms
Using below jQuery I am able to click, but we need to give wait time explicitly for each and every java script that we use, which is time consuming. I am beginner in automation, Kindly help me with a solution.
browser.executeScript("document.getElementsByClassName('cc-button')[0].click()");
My code started running after proving "browser.waitForAngularEnabled(false)" at the start of the script.

How to stop all JS scripts in Puppeteer

I would like to be able to stop any scripts from being able to run in puppeteer after the page has loaded. The reason for this is to stop carousel images and lazy loading images and essentially get the page to behave as statically as possible to enable screenshots where the images aren't changing etc.
By doing page.evaluate('debugger;') it is possible to pause the whole script, but this does not let you continue with taking screen shots as the a evaluate function does not exit until you exit the debugger (If the gui is enabled)
const page = await browser.newPage()
page.setJavaScriptEnabled(false)
If you would like to disable JavaScript after the page has loaded, you can use debugger:
await page.evaluate(() => {
debugger;
});
I was able to take screenshots after using the debugger.
Alternatively, you can replace each original node with its clone to remove the events attached to each element:
await page.evaluate(() => {
document.querySelectorAll('*').forEach(element => {
element.parentNode.replaceChild(element.cloneNode(true), element);
});
});
You can also use removeEventListener() in a loop similar to the one above to remove specific events attached to a node.
Otherwise, if you can disable JavaScript before the page has loaded, you can use page.setJavaScriptEnabled() before navigating to the page:
await page.setJavaScriptEnabled(false);
A better solution is just to block all requests with the type equals to script:
const puppeteer = require("puppeteer");
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on("request", request => {
if (request.resourceType() === "script") {
request.abort()
} else {
request.continue()
}
})
await page.goto("https://stackoverflow.com/")
await browser.close()
})()
Source: Disabling JavaScript Using Puppeteer
If you want to freeze the page and still be able to call evaluate on it, you can
navigate to the page, wait for it to load (and maybe let its JavaScript make some DOM transformations),
get HTML snapshot of the page,
disable JavaScript,
reload the page statically (no DOM transformations will occur since JavaScript is disabled),
profit (do any amount of evaluate or screenshots on a DOM that is guaranteed to stay the same).
await page.goto('<url>', { waitUntil: 'networkidle0' }); // 1
const html = await page.content(); // 2
page.setJavaScriptEnabled(false); // 3
await page.setContent(html, { waitUntil: 'networkidle0' }); // 4
After phoning a friend the following seems to work:
await page.evaluate('document.body.innerHTML = document.body.innerHTML')

Protractor tests are inconsistent even with browser.wait and helper functions

I am looking for some advice. I have been using protractor for a few weeks and just cannot get my tests to be consistent unless I use browser.sleep. I have tried helper functions as well as browser.wait(expectedCondition). I have reduced browser.sleep immensely, but protractor still just goes way to fast. I can never successfully run multiple tests unless I have a few browser.sleeps just so protractor can relax for a second. Here is an example:
The Test I need to select a user, delete that user and wait for a success message. Then I click the same user and click the activate button.
Outcome: Unless I have browser.sleep, my success messages do not even appear after deletion/activation. The tests fail because protractor is moving way too fast. Even with the expected conditions. My main problem is that protractor moves to fast for the angular web page. I have tried ifCLickable or isDisplayed but they do not fix the issue entirely. Here is the code:
async deleteUser() {
await sendClick(this.getNewUser());
await sendClick(this.getDelete());
await waitTillPresent(this.getDeleteConfirm());
await sendClick(this.getDeleteConfirm());
await waitTillPresent(this.getSuccessMsg())
expect(await page.getSuccessMsg().isDisplayed()).toBeTruthy();
}
async activateUser() {
await sendClick(this.getNewUser());
await waitTillPresent(this.getEditBtn())
await sendClick(this.getActive());
await waitTillPresent(this.getSuccessMsg())
expect(await page.getSuccessMsg().isDisplayed()).toBeTruthy();
}
Functions:
export async function sendClick(element: ElementFinder): Promise<boolean> {
try {
if(!await element.isDisplayed()) {
return false;
}
await browser.executeScript('arguments[0].click();', await element.getWebElement());
return true;
}
catch (err) {
return false;
}
}`
export async function waitTillPresent (element: ElementFinder, timeout: number = 10000) {
return browser.wait(() => {
return element.isPresent();
}, timeout);
}
My Question: Am I handling this correctly? Is there a better to ensure my tests are consistent? Before these tests, I visit a non-angular webpage. So I have to include the line browser.waitForAngularEnabled(false)
Does this mess with the async nature of angular? Thank you.
I worked the last few months on our e2e test suite to make it stable. I did not believe it's possible but I made it using correct wait functions and sometimes browser.sleep() as a last resort.
You have a correct approach for waiting for elements. But there are 2 problems regarding your implementation:
1) The function waitTillPresent() does exactly what its name stands for. But if you only wait until the element is present on the page it does not mean it's clickable or displayed. An element can be hidden and at the same time still be present. Please rename waitTillPresent() to waitTillDisplayed() and change it as follows:
export async function waitTillDisplayed(element: ElementFinder, timeout: number = 20000): Promise<boolean> {
let result = await browser.wait(() => element.isPresent(), timeout);
if(!result) {
return false;
}
return await browser.wait(element.isDisplayed(), timeout);
}
2) You should exceed the default timeout. Set it a bit higher like 20 to 25 seconds. Just play with it.
Unfortunately, I don't know how browser.waitForAngularEnabled(false) changes test behavior. We do not use it :)
Note:
These functions are all exactly the same:
function foo() { return 'hello world'; }
var foo = () => { return 'hello world'; };
var foo = () => 'hello world';
Play with arrow functions, it's syntactic sugar.
Cheers and gl!

Protractor - How to obtain the new URL

I am new to Protractor (and Javascript by the way), and I am writing some tests to practice. My goal so far is to check that when I click on the home button of a website, the redirection leads me correctly to the expected address.
I have written this:
var HomeTopBanner = function() {
this.homeUrl = browser.params.homePageObject.homeUrl;
this.topBanner = element(by.css('.navbar-inner'));
this.homeButton = this.topBanner.element(by.css('.icon-home'));
}
describe('Home button', function(){
var homeTopBanner = new HomeTopBanner();
var newUrl = '';
it('clicks on the Home button', function(){
homeTopBanner.homeButton.click();
browser.getCurrentUrl().then(function storeNewUrl(url) {
newUrl = url;
});
})
it('checks that the home button leads to the homepage', function(){
expect(newUrl).toEqual(homeTopBanner.homeUrl);
})
});
This works, but my question is:
Why do I need to separate the "GetCurrentUrl" and the "expect(newUrl)" parts? I would prefer to have both of them in the same spec, but if I do that, during the comparison of the expect, newUrl=''
I assume this is related to browser.getCurrentUrl() being a promise, but is there a better way to do it?
Yes, getCurrentUrl returns a promise with the url in the form of a string as explained in the protractor api docs. You have to wait until the url is returned in order to use it. Now in order to combine both the specs you can write your expect statement inside the function that getCurrentUrl returns as shown below and there is no need of using a newUrl variable too if you want -
it('clicks on the Home button', function(){
homeTopBanner.homeButton.click();
browser.getCurrentUrl().then(function(url) {
expect(url).toEqual(homeTopBanner.homeUrl);
});
})
There could also be another issue when after the click action the previous url is being captured due to the fact that protractor is async and fast. In that case you can write your getCurrentUrl() function inside the promise that click() function returns. Here's an example of it -
it('clicks on the Home button', function(){
homeTopBanner.homeButton.click().then(function(){
browser.getCurrentUrl().then(function(url) {
expect(url).toEqual(homeTopBanner.homeUrl);
});
});
})
Hope this helps.