Can someone help me re-create touch-based gestures(swipe, zoom, pinch, etc.) in Playwright to test emulated mobile devices? It has only a tap method out of the box, which works perfectly, but I need a whole set of functionality to test the mobile viewports of our web application.
I have tried so far a couple of scripts that I found online, which are not failing my tests but rather don't work for me for some reason:
await page.evaluate(() => {
const target = document.querySelector("#abc");
target.addEventListener('touchstart', (e) => {
console.log('touch start');
});
function simulateTouchEvent(element, type, touches) {
const touchEvents = [];
touches.forEach((touch) => {
touchEvents.push(new Touch({
clientX: touch.x,
clientY: touch.y,
identifier: touch.id,
target: element,
}));
});
element.dispatchEvent(new TouchEvent(type, {
touches: touchEvents,
view: window,
cancelable: true,
bubbles: true,
}));
}
simulateTouchEvent(target, 'touchstart', [{
id: "123",
x: 10,
y: 10,
}]);
simulateTouchEvent(target, 'touchend', [{
id: "123",
x: 10,
y: 10,
}]);
})
also this
const el = await page.locator(
".selector"
);
const dataTransfer = await page.evaluateHandle(
() => new DataTransfer()
);
await el.dispatchEvent("touchstart", { dataTransfer, steps: 5 });
await el.dispatchEvent("touchend", { dataTransfer, steps: 5 });
and
async function dispatchTouchEvent(
playWright: Page,
type: 'touchstart' | 'touchend' | 'touchcancel' | 'touchmove',
selector: string,
page?: Position,
screen?: Position,
client?: Position,
options?: PageExtraTouchOptions,
) {
await playWright.$eval(
selector,
(el, options) => {
const rect = el.getBoundingClientRect();
const {
client = {},
page = {},
screen = {},
type,
options: touchOpt,
} = options;
const touchObj = new Touch({
clientX: client.x,
clientY: client.y,
identifier: Date.now(),
pageX:
page.x || (client.x !== undefined ? rect.left + client.x : undefined),
pageY:
page.y || (client.y !== undefined ? rect.top + client.y : undefined),
screenX: screen.x,
screenY: screen.y,
target: el,
});
const touchEvent = new TouchEvent(type, {
bubbles: true,
cancelable: true,
...touchOpt,
changedTouches: [touchObj],
targetTouches: [touchObj],
touches: [touchObj],
});
return el.dispatchEvent(touchEvent);
},
{ client, options, page, screen, type },
);
}
await dispatchTouchEvent(
page,
"touchstart",
".selector"
);
await dispatchTouchEvent(
page,
"touchend",
".selector"
);
I recently have been also looking into Playwrights experimental android emulation feature, in the hopes that it might help me to emulate at least an android device, but haven't even been able to even run it because of ECONNREFUSED error.
Would appreciate any help, because I`m completely stuck in here.
Playwright version: 1.23;
OS: Ubuntu Neon KDE 20.04;
Related
I used react-native-fs to download an image from the server then I used openCropper() from react-native-image-crop-picker to crop. It worked well in iOS, however, it crashed in Android running without any error message or alert.
Have you ever in this issue ? Give me a guide. Thanks everyone.
const onCropImage = async () => {
setViewImageModal(false);
const uri = `${RNFS.DocumentDirectoryPath}/${fileName}`;
let options = {
fromUrl: viewImage && viewImage[0].url,
toFile: uri,
};
await RNFS.downloadFile(options).promise;
// App crashed when I call .openCropper() in Android running
ImageCropPicker.openCropper({
path: uri,
width: 300,
height: 400,
cropping: true,
freeStyleCropEnabled: true,
})
.then((image) => {
if (image) {
const temp = image.path.split("/");
const imageName = temp[temp.length - 1];
navigation.navigate("EditHostScreen", {
host,
type: "hosts",
info: { uri: image.path, typeImage: image.mime, name: imageName },
});
const time = setTimeout(() => {
ImageCropPicker.clean();
if (uri) {
RNFS.unlink(uri);
}
}, 100000);
clearTimeout(time);
}
})
.catch((err) => {
// console.log(err);
});
};
You need to add the android specific path value.
import { Platform } from 'react-native';
ImageCropPicker.openCropper({
path: Platform.OS === "android" ('file://' + uri) : uri,
width: 300,
height: 400,
cropping: true,
freeStyleCropEnabled: true,
})
I am trying to develop a hybrid ol3 map application using ionic3 with angularjs. I have generated xyz tiles of the map service which I was able to use for online maps. When I tried using them for download to a local directory of mobile and use them I am facing issues. Kindly provide any help which is much appreciated. I I could not trace any errors. Kindly suggest me how to check if any errors to test the maps.
//For downloading the image from server and stores it into mobile directory.
this.file.createDir(this.file.externalRootDirectory, 'Offline/Maps/custom_', true).then((files) => {
this.file.createDir(this.file.externalRootDirectory, 'Offline/Maps/custom_/02_02', true).then((files) => {
}).catch((err) => {
});
}).catch((err) => {
});
const imageURL = 'https://server.com/documents/ionic/path_track/maps/0041_0041.jpeg';
const fileTransfer: FileTransferObject = this.transfer.create();
const imageName = imageURL.split('/').pop();
//alert(imageName+"#"+this.file.externalRootDirectory);
//alert(imageName);
fileTransfer.download(imageURL, this.file.externalRootDirectory+'Offline/Maps/custom_07/02_02/'+imageName).then((entry) => {
//loader.dismiss();
//this.showOfflineButton = true;
}, (error) => {
let alert = this.alertCtrl.create({
message: 'Map is not downloaded '+JSON.stringify(error),
buttons: ['Ok'],
enableBackdropDismiss: false,
cssClass:'alert-error'
});
alert.present();
});
//For retrieving image from the mobile directory and to display into mobile app.
var config = {
"bounds": {
"left" : 68.1060582899974,
"bottom" : 6.72246026992798,
"right" : 97.7525939941406,
"top" : 37.0967391635301
}
};
var bounds = [config.bounds.left, config.bounds.bottom, config.bounds.right, config.bounds.top];
var resolutions = [
0.1186495269281333,
0.0593247634640666,
0.0296623817320333,
0.0148311908660167,
0.0074155954330083,
0.0037077977165042,
0.0018538988582521,
0.000926949429126,
0.000463474714563,
0.0002317373572815,
0.0001158686786408,
0.0000579343393204,
0.0000289671696602,
0.0000144835848301,
0.000007241792415
];
var projection_epsg_no = 4326
var layername = 'seamless_xyz1';
var tileGrid = new ol.tilegrid.TileGrid({
extent: bounds,
resolutions: resolutions,
origin: ol.extent.getTopLeft(bounds),
projection: 'EPSG:4326',
tileSize: [256, 256]
});
var view = new ol.View({
extent: [55.948355423604156, 4.853611184459009, 101.73937104860416, 38.07626743445901],
zoom: 10,
center: [78.48695, 17.41217],
projection: 'EPSG:4326',
resolutions: resolutions
});
var tms_source = new ol.source.XYZ({
projection: 'EPSG:4326',
tileGrid: tileGrid,
url: this.file.externalRootDirectory+'/Offline/Maps/custom_{z}/{x}/{-y}.jpeg'
//url: this.file.externalRootDirectory+'/Offline/Maps/custom_07/02_02/0041_0043.jpeg' (If I am giving static image name then its coming fine but not able to do it dynamically.)
});
var basegroup = new ol.layer.Tile({
source: tms_source,
extent: bounds
});
var mapview;
if(this.Source_lat == undefined || this.Source_long == undefined){
this.current_location1 = 'Location is not available.';
mapview = new ol.View({
projection: 'EPSG:4326',
center: [82.491,21.899],
extent: [66.2329, 7.68083, 98.2223, 39.03874],
maxZoom:16,
minZoom: 8,
zoom: 8
});
}else{
this.current_location1 = this.Source_lat+', '+this.Source_long;
mapview = new ol.View({
projection: 'EPSG:4326',
center: [this.Source_long,this.Source_lat],
extent: [66.2329, 7.68083, 98.2223, 39.03874],
maxZoom:10,
minZoom: 10,
zoom: 10
});
}
map = new ol.Map({
target: 'offline_map',
controls: ol.control.defaults({
zoom: false,
attribution: false,
rotate: false
}),
layers: [basegroup, jsonLayer_net1, jsonLayer_net],
overlays: [jsonoverlay],
view: mapview
});
Thanks in advance
I am trying to create an excel sheet from React Native mobile application. I have tried using xlsx to generate excel. But it is not supporting the styling excel sheet. Is it possible to use ExcelJS in React Native?
Yes, it is possible with the help of Google spreadsheet and tabletop library. After searching a lot I found this way:
Install the tabletop library.
Upload your .xlsx file in google drive.
Now in select File -> Share-> Publish to web.
Once you click a new window open and your file published.
Now close this window and copy the key of your file.
The Key will be found in the URL of the browser.
Forex:
https://docs.google.com/spreadsheets/d/108O2Memo7yJ3-7fzngFSoulVj-J32vwcyLDu5Lslhik/edit#gid=1371815480
In the above URL: this will be the key "108O2Memo7yJ3-7fzngFSoulVj-J32vwcyLDu5Lslhik"
6. Now in your code pass this key to the init method of the tabletop.
7. Get data from the file and show it in the list.
Library install :
npm install tabletop
In component did mount I initialize tabletop.
componentDidMount() {
// Facts
Tabletop.init({
key: 'keyCopyFromUrl',
callback: googleData => {
this.setState({
arrayFacts: googleData
})
},
simpleSheet: true
});
Now for showing this data
<FlatList
data={this.state.arrayFacts}
renderItem={this.renderItemFacts}
keyExtractor={(key, index) => index.toString()}
/>
First of all install the required modules (assuming usage of Expo):
npm install --save exceljs
expo install expo-file-system
expo install expo-sharing
Code example - Imports:
// Required to save to cache
import * as FileSystem from 'expo-file-system';
// ExcelJS
import ExcelJS from 'exceljs';
// From #types/node/buffer
import { Buffer as NodeBuffer } from 'buffer';
// Share excel via share dialog
import * as Sharing from 'expo-sharing';
Code example - Function to generate Excel and return uri
// This returns a local uri that can be shared
const generateShareableExcel = async (): Promise<string> => {
const now = new Date();
const fileName = 'YourFilename.xlsx';
const fileUri = FileSystem.cacheDirectory + fileName;
return new Promise<string>((resolve, reject) => {
const workbook = new ExcelJS.Workbook();
workbook.creator = 'Me';
workbook.created = now;
workbook.modified = now;
// Add a sheet to work on
const worksheet = workbook.addWorksheet('My Sheet', {});
// Just some columns as used on ExcelJS Readme
worksheet.columns = [
{ header: 'Id', key: 'id', width: 10 },
{ header: 'Name', key: 'name', width: 32 },
{ header: 'D.O.B.', key: 'dob', width: 10, }
];
// Add some test data
worksheet.addRow({ id: 1, name: 'John Doe', dob: new Date(1970, 1, 1) });
worksheet.addRow({ id: 2, name: 'Jane Doe', dob: new Date(1969, 2, 3) });
// Test styling - what OP wanted
worksheet.eachRow((row, rowNumber) => {
row.getCell(1).font = {
name: 'Arial Black',
color: { argb: 'FF00FF00' },
family: 2,
size: 14,
bold: true
};
});
// Write to file
workbook.xlsx.writeBuffer().then((buffer: ExcelJS.Buffer) => {
// Do this to use base64 encoding
const nodeBuffer = NodeBuffer.from(buffer);
const bufferStr = nodeBuffer.toString('base64');
FileSystem.writeAsStringAsync(fileUri, bufferStr, {
encoding: FileSystem.EncodingType.Base64
}).then(() => {
resolve(fileUri);
});
});
});
}
Code Example - Function to share generated Excel. Call this, for example, on the press of a button:
const shareExcel = async () => {
const shareableExcelUri: string = await generateShareableExcel();
Sharing.shareAsync(shareableExcelUri, {
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // Android
dialogTitle: 'Your dialog title here', // Android and Web
UTI: 'com.microsoft.excel.xlsx' // iOS
}).catch(error => {
console.error('Error', error);
}).then(() => {
console.log('Return from sharing dialog');
});
}
I need to show custom icons in my places, that icons are loaded from a specific URL dynamically. Here is my code.
const PlacesMarker = props => {
const { places } = props
const [geoJson, setGeoJson] = useState([])
useEffect(() => {
if (places)
renderPlaces(places)
}, [places])
const renderPlaces = (places) => {
let features = places.content.map((item) => {
return {
type: "Feature",
id: item.id,
properties: {
id: item.id,
icon: item.type.iconUri,
name: item.name,
type: item.type.name
},
geometry: {
type: "Point",
coordinates: [item.location.lon, item.location.lat],
},
}
})
setGeoJson(features)
}
return (
<View>
{geoJson.length > 0 ?
<MapboxGL.ShapeSource id={'places-map'}
shape={{ type: "FeatureCollection", features: geoJson }}>
<MapboxGL.SymbolLayer
id={Math.random().toString()}
style={{
iconImage: ['get', 'icon']
iconAllowOverlap: true,
// iconSize: 0.80,
iconIgnorePlacement: true,
textField: ['get', 'icon']
}}
/>
</MapboxGL.ShapeSource> : null
}
</View >
)
}
export default PlacesMarker
In the style, I used the expression 'get', and it works, because I set the textField with Icon URI value and it shows the uri. However if I set the iconImage property with the URI, then the icon appear successfully
In react-native-mapbox-gl 7.0 if iconImage is constant then you can use url-s. But if it's an expression it should be a key in images dict of Images, <Images images={images} />.
See https://github.com/react-native-mapbox-gl/maps/issues/652
I'm trying to send an image from an android device to a laravel api using react native, but it doesn't read the url of the image, i.e Unable to init from given url (file:///storage/emulated/0/DCIM/Camera/IMG_20181013_133327.jpg, it always brings that error, it doesn't read the url of the image, file:///storage/emulated/0/DCIM/Camera/IMG_20181013_133327.jpg please how can I send the image to my laravel api successfully or I can I download based on the location of the image on the android device
REACT NATIVE AXIOS
//THE IMAGES ARE FIRST SELECTED AND THE IMAGES ARRAY IS SET WITH THE URI OF THE IMAGES
imageUpload(){
ImagePicker.openPicker({
multiple: true,
cropping: true,
mediaType: 'photo'
}) .then(images => {
console.log(images);
const imagesArray = [];
if(images){
images.map(i => {
imagesArray.push({uri: i.path, type: i.mime, name: i.path});
} );
}
this.setState({
images_array: imagesArray
});
console.log(imagesArray);
console.log(this.state.images_array);
}).catch(e => console.log(e));
}
//THE IMAGES ALONG WITH OTHER DETAILS ARE SENT TO THE LARAVEL API
seller(){
this.setState({loader: true});
var data = {
name: this.state.name,
// user_id: this.state.user_id,
user_id: 18,
description: this.state.description,
amount: this.state.amountT,
qty: this.state.qty,
cat_id: this.state.cat_id,
photos: this.state.images_array
};
/* var config = {
headers: {'Authorization': "Bearer " + this.state.token}
};*/
axios.post(
'http://10.0.2.2:8000/api/sell',
data,
// config
).then((response) => {
this.setState({loader: false});
console.log(response);
Alert.alert(
'Success',
'Product posted Successfully',
[
{text: 'OK', onPress: this.props.navigation.navigate('Land', {})},
], );
}).catch((error) => {
this.setState({loader: false});
Alert.alert(
'Error',
'Internal Server Error, please try again later',
[
{text: 'OK'},
], );
console.log(error);
});
};
LARAVEL BACKEND, i.e Intervention Image api is used
public function imagesUpload($goodsId, $photos){
$images = $photos;
// $count = $images->count;
foreach($images as $image){
$uri = $image['uri'];
$filename = basename($uri);
Image::make($uri)->save(public_path('img/' . $filename));
$saver = new Images;
$saver->product_id = $goodsId;
$saver->location_url = 'img/'.$filename;
$saver->save();
}
return true;
}
using double // does not work on real devices , it may work on emulator but not on real devices .
try using this
uri:'file:///storage/emulated/0/DCIM/IMG_20161201_125218.jpg'
make sure to use /// three forward slashes.