TestCafe persist data when clicking - javascript

In TestCafe, on click of an anchor tag, I have a redirect to a new page and an event that basically logs the click event to an object.
I'm wanting to test the value of the click event in the object in TestCafe, but because the redirect happens, I lose the object.
Manually I'm able to do this, as I can hold shift while clicking the link and open a new window for the redirected page, but keep the original page in the original window and then see the object in the console.
Trying to figure out if there's a way "simulate" a click, but not do the redirect. Or alternatively, be able to assert somehow immediately after the click, but before the redirect?
mini example:
await t
.click('a') // here it already redirects so I'll lose the object
.expect(object).contains('value')

The following test shows how you can disable and enable navigation for a link:
import { Selector, ClientFunction } from 'testcafe';
fixture `Navigation`
.page `example.com`;
const enableNavigationControl = ClientFunction(selector => {
const element = selector();
element.addEventListener('click', event => window.disableNavigation && event.preventDefault());
});
const disableNavigation = ClientFunction(() => window.disableNavigation = true);
const enableNavigation = ClientFunction(() => window.disableNavigation = false);
test('navigation', async t => {
const link = Selector('a');
await enableNavigationControl(link);
await disableNavigation();
await t.click(link);
// Perform assertions...
await enableNavigation();
await t.click(link);
});

Related

#Return same screen after refresh

I am developing a page that use a ajax request to read a JSON file and I am displaying it
by looping on clicks
but when I refresh page it returns to first screen is there anyway to return the same screen after
I refresh
please no JQUERY
Here I have made a "framework" for maintaining the stat of your page.
The AJAX request happens when the hash in the URL changes (here the state is "state1": http://example.org/#state1). There is an event listener for the hashchange event and a function fetshdata().
When clicking the button "Get Data", the hash will change, the hashchange event will happen and the function fetshdata() will be called.
If the page is reloaded (this is your problem) the "state" of the page is maintained in the hash (the hash is still in the URL). To tricker the hashchange event I made the hashchange event "by hand" and dispatch it on the window.
The state of the page could also be maintained in localStorage, but the advantage with the hash in the URL is that the hash change becomes part of the history in the browser and you can save/send/link to the URL etc.
const data = 'data:application/json;base64,W3sidGl0bGUiOiJJdGVtIDEifSx7InRpdGxlIjoiSXRlbSAyIn0seyJ0aXRsZSI6Ikl0ZW0gMyJ9XQ==';
var content;
const fetchdata = hash => {
let url = hash; //use the hash as part of the AJAX request (not implemented)
fetch(data).then(res => res.json()).then(json => {
content.innerHTML = '';
json.forEach(item => {
content.innerHTML += `<p>${item.title}</p>`;
});
});
};
document.addEventListener('DOMContentLoaded', e => {
content = document.getElementById('content');
document.getElementById('btn_load').addEventListener('click', e => {
location.hash = 'newstate';
});
document.getElementById('btn_reload').addEventListener('click', e => {
location.reload();
});
if(location.hash){
let event = new Event('hashchange');
window.dispatchEvent(event);
}
});
window.addEventListener('hashchange', e => {
let hash = location.hash.substring(1);
fetchdata(hash);
});
<button id="btn_load">Get data</button>
<button id="btn_reload">Reload</button>
<div id="content"></div>

JavaScript Differentiate Between Page Refresh, Browser Close and New tab

I am trying to Differentiate Between Page Refresh, Browser Close and New tab events.
So, I want some handling on page close V/s page refresh/new tab
I came across below workaround using sessionStorage. However the issue with sessionStorage is that it gets reset or is not read even on opening link in new tab. But I want both page refresh/new tab to behave in same way V/s refresh of the page.
if (sessionStorage.getItem('reloaded') != null) {
console.log('page was reloaded');
} else {
console.log('page was not reloaded');
}
sessionStorage.setItem('reloaded', 'yes');
You'll have to use a combination of sessionStorage and localStorage to persist the data and rely on beforeunload event to handle the data removal.
The thing is beforeunload fires on both tab/window close and page refresh so we have to work around that.
localStorage will handle persistence across tabs and windows and sessionStorage will sync the data on page refresh.
const readFromStorage = (storageKey) => {
const localStorageItem = localStorage.getItem(storageKey);
const sessionStorageItem = sessionStorage.getItem(storageKey);
// You can optimize this by doing more checks but you get the idea
const itemValue = localStorageItem ?? sessionStorageItem;
if (localStorageItem !== sessionStorageItem) {
writeToStorage(storageKey, itemValue);
}
return itemValue;
};
const writeToStorage = (storageKey, value) => {
localStorage.setItem(storageKey, value);
sessionStorage.setItem(storageKey, value);
};
Event handler:
window.addEventListener('beforeunload', (e) => {
localStorage.removeItem(STORAGE_KEY);
});
Usage:
const STORAGE_KEY = '<storage_key>';
const item = readFromStorage(STORAGE_KEY);
If item is null - a tab/windows was closed. Otherwise, the data will persist across refreshes and new tabs/windows.

Playwright page.click scrolls too much

Given I want to record the action being done the page, when clicking on an element
Playwright scrolls the page until the element is on top of the page, even though before the action the element is visible in the viewport.
P.S. the option "scroll: false" does nothing
code snippet:
await Promise.all([
global.page.waitForNavigation(),
global.page.click(global.identifier, { scroll: false })
]);
L.E.:
I want to add some more details about my issue using an example:
So, let's assume I want to do a click action on the "Answer your question" button, and page looks like this:
after the click is performed the page automatically scrolls, putting the button on top of the page, like this:
My expectation is, if the element is in viewpoint, just to perform the action, without scrolling or moving the viewpoint.
I also faced this issue so I resolve this by doing scroll into the view function reference
await page.$eval(ele, (element) => {
element.scrollIntoView();
});
So here's the full code
const playwright = require('playwright');
const moment = require('moment');
(async () => {
const browser = await playwright.chromium.launch({
headless: false,
args: ['--disable-notifications']
});
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://stackoverflow.com/questions/68127885/playwright-page-click-scrolls-too-much');
await page.waitForSelector('.js-accept-cookies')
.then(() => page.click('.js-accept-cookies') );
let ele = '#submit-button';
await page.$eval(ele, (element) => {
element.scrollIntoView();
});
await page.click(ele);
let date = moment();
await page.screenshot({ path: `example-scroll-${date}.png` });
await browser.close();
})();
Attaching screenshot for reference:

Only show Popup one time with React (local storage)

I would like to show the popup only one time with React Hooks.
Access for the first time to example.com/campaign/1234
Show popup
Close or refresh the page.
Access again to example.com/campaign/1234 and don't show popup
Access for the first time to example.com/campaign/0000 (is a different URL)
Show popup
Close or refresh the page
Access again to example.com/campaign/0000 or example.com/campaign/1234 and the popup is not being displayed
Any idea of how to do it? I know that I need to use local storage but how can I trigger the event when the user closes or refreshes the page?
Here is a sandbox.
I also read this thread but it doesn't mention how to do it with Hooks
If you never use the setStickyState callback from the custom hook, the state will just remain at its initial value.
It seems like setStickyState also has a bug in it, where it won't update if the key has changed. Here's an enhanced version that I've called useLocalStorage, which should work more reliably:
export function useLocalStorage(key, initialDefault) {
const [val, setVal] = useState(() => {
const localStorageVal = localStorage.getItem(key);
return localStorageVal !== null
? JSON.parse(localStorageVal)
: initialDefault;
});
useEffect(() => {
if (localStorage.getItem(key) === null) {
setVal(initialDefault);
}
}, [key, initialDefault]);
useEffect(() => {
localStorage.setItem(key, JSON.stringify(val));
}, [val, key]);
return [val, setVal];
}
You can then use it like this:
const [visited, setVisited] = useLocalStorage(pageId, false);
const navigateAway = useCallback(() => {
setVisited(true)
}, [setVisited])
useEffect(() => {
// if user navigates away to a completely different site
// or refreshes the page etc
window.addEventListener("beforeunload", navigateAway);
// if user navigates to another page on the same site
return () => {
navigateAway();
window.removeEventListener("beforeunload", navigateAway);
};
}, [pageId, navigateAway]);
// ...
<dialog open={!visited}>
<p>Welcome to page {pageId}!</p>
<button onClick={() => setVisited(true)}>
Don't show again on this page
</button>
</dialog>
Here's a demo (with TypeScript):
useLocalStorage demo

Unable to attach new click event handlers on HTML element using Puppeteer

Why is the on click event on anchor not triggering while manually clicking in a debug session from VS Code?
Broadly here is my goal:
Go to linkedin.com using Puppeteer in headful Chrome
Login
Go to linkedin.com/jobs
Attach a click event handler for all the links on the page
Pause the node.js execution after attaching the event handlers
Click the links manually with my mouse to observe this new event handler in action
In code, this is what I got
const puppeteer = require('puppeteer')
async function main() {
const browser = await puppeteer.launch({ headless: false })
const page = await browser.newPage();
await page.goto('https://www.linkedin.com/');
await login(page);
await page.goto('https://www.linkedin.com/jobs/');
await attachLinks(page);
await page.screenshot({ path: "bla" })
browser.close();
};
async function attachLinks(page) {
const bodyHandle = await page.$('body');
await page.evaluate( (body, numLinks=3) => {
let anchors = Array.from( body.querySelectorAll("a") ).
filter( (e, i) => i < numLinks );
for(let i = 0; i < anchors.length; i++) {
let a = anchors[i];
console.log(`Binding for ${a.href}`);
// This event does not trigger!!!!!
a.addEventListener("click", e => {
console.log("some one clicked the link");
e.preventDefault();
e.stopPropagation();
return false;
});
};
}, bodyHandle);
await bodyHandle.dispose();
}
main();
Then using VS Code and node.js debugging support, I put a breakpoint on line await page.screenshot({ path: "bla" }) after the onclick event for <a> tags is attached. In the browser that opens (as headless is set to false), while the code is waiting to be resumed, I clicked the <a> tags in the <body> with my mouse, expecting to see "some one clicked the link" in the headful debug Chrome browser's console. But I dont see a logs either in the browser or in VS Code's Debug console. Am I missing something here?
That's because you are not actually clicking the anchor tag. You've attached an event to it "click" and defined what will happen when we will click it, but you're not actually clicking it. Just add a.click() like
// This event will now trigger
a.addEventListener("click", e => {
console.log("some one clicked the link");
e.preventDefault();
e.stopPropagation();
return false;
});
a.click();
see the name addEventListener, you're attaching an event listener, not actually clicking it

Categories