Playwright waitForFunction for mouse? - storybook

I would like to make a screenshot of a hovered button in storybook. My code not working with headless browsers and I probably need to wait some more but can't seem to figure it out. I'm very grateful for any tips.
test('example test', async ({ url }) => {
const browser = firefox.launch({ headless: false, slowMo: 300 });
const page = await (await browser).newPage();
await page.goto(
'url'
);
await page.waitForNavigation({ waitUntil: 'load' });
await page.waitForSelector('#storybook-preview-iframe');
const elementHandle = await page.$('#storybook-preview-iframe');
const frame = await elementHandle.contentFrame();
await frame.waitForSelector('button[id=btn]');
const el = await frame.$('button[id=btn]');
const box = await el.boundingBox();
// const watchDog = page.waitForFunction(
// page => {
// page.mouse; ??????????????? I know that there is no mouse.getCurrentPosition method
// },
// {},
// page
// );
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
//await watchDog;
expect(await page.screenshot()).toMatchSnapshot('screenshot.png');
});

You can use page.hover() as this method will scroll view into the selected element then move the cursor over the element.
https://pptr.dev/#?product=Puppeteer&version=v13.5.1&show=api-pagehoverselector
test('example test', async ({ url }) => {
const browser = firefox.launch({ headless: false, slowMo: 300 });
const page = await (await browser).newPage();
await page.goto(
'url'
);
await page.waitForNavigation({ waitUntil: 'load' });
await page.waitForSelector('#storybook-preview-iframe');
const elementHandle = await page.$('#storybook-preview-iframe');
const frame = await elementHandle.contentFrame();
await frame.waitForSelector('button[id=btn]');
await frame.hover('button[id=btn]')
expect(await page.screenshot()).toMatchSnapshot('screenshot.png');
});
That's it. Hope this will work.

Related

waitForResponse does not work in the cluster.tasks callback

I need to open 20 pages parallelly and click on a button then wait for a response after that get the data from a tag. and my code is:
async function getPageData(links) {
return new Promise(async (resolve, reject) => {
try {
const cluster = await Cluster.launch({
concurrency: Cluster.CONCURRENCY_PAGE,
maxConcurrency: 200,
monitor: true,
});
let allData = [];
await cluster.task(async function getData({ page, data: url }) {
await page.goto(url, {
waitUntil: 'networkidle2',
});
const buttonQuery = 'button[role=tab]:first-child';
const buttonElement = await page.waitForSelector(buttonQuery);
await buttonElement.click(buttonElement);
await page.waitForResponse('https://XXX'); // the problem is here
const data = await page.evaluate(getList);
const [oscillators, summary, movingAverage] = data;
allData.push({ oscillators, summary, movingAverage });
});
links.map(async function addQueue(link) {
cluster.queue(link);
});
await cluster.idle();
await cluster.close();
resolve(allData);
} catch (e) {
reject(e);
}
});
but it just work for the first time and ignore the rest of the tasks. but when I remove page.waitForResponse() the all tasks will be run as expected.
How can I make all tasks wait for their response then extract the data?

Upload base64 image to Google Cloud Storage - Expo/React Native [duplicate]

Error given: [Unhandled promise rejection: FirebaseError: Firebase Storage: String does not match format 'data_url': Must be formatted 'data:[][;base64], (storage/invalid-format)]
I am able to add image to the database, however it is not uploading to the firebase storage. I have changed it to different media types but no luck. I have also tired uploadBytes instead of uploadString and it works but no image displays. Any help would be appreciated!
const uploadImageTops = async () => {
const docRef = await addDoc(collection(db, "tops"), {
username: "user",
apparel: "tops",
color: "black",
size: size,
timeStamp: serverTimestamp(),
});
const imageRef = ref(storage, `tops/${docRef.id}`);
await uploadString(imageRef, cameraImage, "data_url", {contentType:'image/jpg'})
.then(async (snapshot) => {
const downloadURL = await getDownloadURL(imageRef);
await updateDoc(doc(db, "tops", docRef.id), {
imageUrl: downloadURL,
});
})
.then(navigation.navigate("Home"));
};
There's some issue with react-native and firebase when trying to upload the image. Blob is needed to upload image to firebase storage and firestore. Add that blob at the top and make sure you close the blob at the end.
This code worked for me.
const uploadImageTops = async () => {
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
console.log(e);
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", cameraImage, true);
xhr.send(null);
});
const docRef = await addDoc(collection(db, "tops"), {
username: user,
apparel: "tops",
color: color,
size: size,
timeStamp: serverTimestamp(),
});
const imageRef = ref(storage, `tops/${docRef.id}`);
const metadata = {
contentType: "image/jpeg",
};
await uploadBytes(imageRef, blob, metadata)
.then(async (snapshot) => {
const downloadURL = await getDownloadURL(imageRef);
await updateDoc(doc(db, "tops", docRef.id), {
imageUrl: downloadURL,
});
blob.close();
})
.then(navigation.navigate("Home"));
};

Trying to add a image to firebase V9 storage with react-native expo and redux

Error given: [Unhandled promise rejection: FirebaseError: Firebase Storage: String does not match format 'data_url': Must be formatted 'data:[][;base64], (storage/invalid-format)]
I am able to add image to the database, however it is not uploading to the firebase storage. I have changed it to different media types but no luck. I have also tired uploadBytes instead of uploadString and it works but no image displays. Any help would be appreciated!
const uploadImageTops = async () => {
const docRef = await addDoc(collection(db, "tops"), {
username: "user",
apparel: "tops",
color: "black",
size: size,
timeStamp: serverTimestamp(),
});
const imageRef = ref(storage, `tops/${docRef.id}`);
await uploadString(imageRef, cameraImage, "data_url", {contentType:'image/jpg'})
.then(async (snapshot) => {
const downloadURL = await getDownloadURL(imageRef);
await updateDoc(doc(db, "tops", docRef.id), {
imageUrl: downloadURL,
});
})
.then(navigation.navigate("Home"));
};
There's some issue with react-native and firebase when trying to upload the image. Blob is needed to upload image to firebase storage and firestore. Add that blob at the top and make sure you close the blob at the end.
This code worked for me.
const uploadImageTops = async () => {
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
console.log(e);
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", cameraImage, true);
xhr.send(null);
});
const docRef = await addDoc(collection(db, "tops"), {
username: user,
apparel: "tops",
color: color,
size: size,
timeStamp: serverTimestamp(),
});
const imageRef = ref(storage, `tops/${docRef.id}`);
const metadata = {
contentType: "image/jpeg",
};
await uploadBytes(imageRef, blob, metadata)
.then(async (snapshot) => {
const downloadURL = await getDownloadURL(imageRef);
await updateDoc(doc(db, "tops", docRef.id), {
imageUrl: downloadURL,
});
blob.close();
})
.then(navigation.navigate("Home"));
};

How to capture dynamic content from element inside an iFrame?

When I try to capture text from an element inside an iFrame where the element content changes every second, I get "undefined". What might I be doing wrong?
Code:
const { firefox } = require('playwright');
const fs = require('fs');
var url = 'http://jsfiddle.net/6vnam1jr/1/show';
var section_path = 'xpath=/html/body/div/div/div/section';
var iframe_path = 'xpath=/html/body/div/iframe';
var text_path = 'xpath=//html/body/div[2]/div[2]';
async function getElementText(browser,page){
await page.goto(url);
await page.click(section_path);
const frame = await page.$(iframe_path);
const contentFrame = await frame.contentFrame();
await sleep(1000);
let handle = await contentFrame.$eval(text_path);
console.log(handle)
// try again
await sleep(1000);
handle = await contentFrame.$eval(text_path);
console.log(handle)
closeBrowser(browser);
}
async function closeBrowser(browser){
await browser.close();
}
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
(async () => {
const browser = await firefox.launch({ headless: false });
const page = await browser.newPage();
getElementText(browser,page);
})();```
Thanks for the repro. frame.$eval is an API to run a JS function in the browser which takes the element as an argument.
I believe what you are looking for is an ElementHandle to this element. You can use frame.waitForSelector or frame.$ for this purpose. I have verified that they are not undefined.
// ...
let handle = await contentFrame.waitForSelector(text_path);

How can I return the download URL of an image uploaded to firebase storage

I want to upload an image to firebase (which is working), then return the download URL of the image and store it as a string.
Here is my code:
uploadImage = async (uri, imageName) => {
const response = await fetch(uri);
const blob = await response.blob();
firebase.storage().ref().child(imageName).put(blob)
.then(snap => {
return snap.ref.getDownloadURL();
})
.then(downloadURL => {
return downloadURL;
})
.catch(error => {
console.log(`An error occurred while uploading the file.\n\n${error}`);
});
}
The image uploads to firebase storage just fine. At the moment it just shows this when I try write the URL of the uploaded image to the database:
https://ibb.co/WHHHxBY
Here is the block of code where I create the user record:
firebase
.auth()
.createUserWithEmailAndPassword(this.state.email, this.state.password)
.then(userCredentials => {
let imageUrl = '';
let db = firebase.database().ref('users/' + userCredentials.user.uid);
if (this.state.image) {
imageUrl = this.uploadImage(this.state.image.uri, `images/user-${userCredentials.user.uid}`);
}
db.set({
email: this.state.email,
imageUrl: imageUrl,
username: this.state.username
});
return userCredentials.user.updateProfile({
displayName: this.state.username
});
})
.catch(error => this.setState({ errorMessage: error.message }));
In your uploadImage function, you are chaining the promises but you don't return the chain. You should adapt it as follows:
uploadImage = async (uri, imageName) => {
const response = await fetch(uri);
const blob = await response.blob();
return firebase.storage().ref().child(imageName).put(blob) // <-- Here return the chain
.then(snap => {
return snap.ref.getDownloadURL();
})
.then(downloadURL => {
return downloadURL;
})
.catch(error => {
console.log(`An error occurred while uploading the file.\n\n${error}`);
});
}
However, you could transform this code in async/await "style", as follows:
uploadImage = async (uri, imageName) => {
try {
const response = await fetch(uri);
const blob = await response.blob();
const snap = await firebase.storage().ref().child(imageName).put(blob);
const downloadURL = await snap.ref.getDownloadURL();
return downloadURL;
} catch (e) {
console.error(e);
throw e;
}
}
Then, since this uploadImage function is asynchronous you should adapt the way you call it. I suggest to modify the other part of your code as follows:
try {
const userCredentials = await firebase
.auth()
.createUserWithEmailAndPassword(this.state.email, this.state.password);
let imageUrl = '';
const db = firebase.database().ref('users/' + userCredentials.user.uid);
if (this.state.image) {
imageUrl = await this.uploadImage(this.state.image.uri, `images/user-${userCredentials.user.uid}`);
await db.set({
email: this.state.email,
imageUrl: imageUrl,
username: this.state.username
});
return userCredentials.user.updateProfile({
displayName: this.state.username
});
}
//You should probably manage the else case
} catch (e) {
this.setState({ errorMessage: e.message })
}

Resources