So, I write TAF to automate user cases using Cypress. I'm a novice in it.
I need to return from Cypress each
mand a Map
with some values to use it in next mand as input value.
In DOM there are some amount of canvas
tags like this:
<canvas class="leaflet-tile leaflet-tile-loaded" width="256" height="256" style="width: 256px; height: 256px; transform: translate3d(613px, 246px, 0px); opacity: 1;"></canvas>
From style
attribute I need to extract two coordinates, so, just transform value:
width: 256px; height: 256px; transform: translate3d(613px, 246px, 0px); opacity: 1;
to
613 246
and set it like a key to Map object. And as value I need to set a buffer of encoded canvas data.
So, I add custom mand like this:
function convertCanvasMatrixToPictureCommand() {
Cypress.Commands.add('renderCanvasMatrixToPng', { prevSubject: true }, (subject, savePath) => {
const bufferMap = new Map();
cy.wrap(subject)
.each(canvas => {
Cypress.Blob.canvasToBlob(canvas.get(0))
.then(blob => Cypress.Blob.blobToArrayBuffer(blob))
.then(buff => {
const coordinates = extract(canvas.attr('style'));
const buffer = Buffer.from(buff);
bufferMap.set(coordinates, buffer);
});
// and here in some way I need to return bufferMap obj
// to use it as input data in next cypress task:
})
.task('mergeImages', { buffers: bufferMap, savePath: 'cypress/snapshots' });
});
}
mergeImages
task will proceed the map and using specified sorting, merge all canvases to a single PNG
image.
But is it possible in some way to return this map from each
mand?
This bufferMap
object valid only inside each mand. But out of each
it still empty
cy.wprap()
also not resolve this issue. Or I use it incorrect...
Thanks!
So, I write TAF to automate user cases using Cypress. I'm a novice in it.
I need to return from Cypress each
mand a Map
with some values to use it in next mand as input value.
In DOM there are some amount of canvas
tags like this:
<canvas class="leaflet-tile leaflet-tile-loaded" width="256" height="256" style="width: 256px; height: 256px; transform: translate3d(613px, 246px, 0px); opacity: 1;"></canvas>
From style
attribute I need to extract two coordinates, so, just transform value:
width: 256px; height: 256px; transform: translate3d(613px, 246px, 0px); opacity: 1;
to
613 246
and set it like a key to Map object. And as value I need to set a buffer of encoded canvas data.
So, I add custom mand like this:
function convertCanvasMatrixToPictureCommand() {
Cypress.Commands.add('renderCanvasMatrixToPng', { prevSubject: true }, (subject, savePath) => {
const bufferMap = new Map();
cy.wrap(subject)
.each(canvas => {
Cypress.Blob.canvasToBlob(canvas.get(0))
.then(blob => Cypress.Blob.blobToArrayBuffer(blob))
.then(buff => {
const coordinates = extract(canvas.attr('style'));
const buffer = Buffer.from(buff);
bufferMap.set(coordinates, buffer);
});
// and here in some way I need to return bufferMap obj
// to use it as input data in next cypress task:
})
.task('mergeImages', { buffers: bufferMap, savePath: 'cypress/snapshots' });
});
}
mergeImages
task will proceed the map and using specified sorting, merge all canvases to a single PNG
image.
But is it possible in some way to return this map from each
mand?
This bufferMap
object valid only inside each mand. But out of each
it still empty
cy.wprap()
also not resolve this issue. Or I use it incorrect...
Thanks!
Share Improve this question asked Feb 17, 2020 at 10:23 Roman ShmandrovskyiRoman Shmandrovskyi 9834 gold badges11 silver badges22 bronze badges2 Answers
Reset to default 3A couple of problems with the custom mand
to make sure you wait on the results of
.each()
, must return the promise created btCypress.Blob.canvasToBlob()
chain.follow the
.each()
with a.then()
to ensure pletion, and return `bufferMap here.
Problems with .task()
it does not like being called within the custom mand, so call it after
CypressError: cy.then() failed because you are mixing up async and sync code.
it does not like a
Map()
object as a parameter, convert to a plain object
Test
describe('leaflet', () => {
it('processes', () => {
Cypress.Commands.add('renderCanvasMatrixToPng', {prevSubject: true}, (subjects, savePath) => {
const bufferMap = new Map();
cy.wrap(subjects)
.each((canvas, i) => {
return Cypress.Blob.canvasToBlob(canvas.get(0)) // <- add return here
.then(blob => Cypress.Blob.blobToArrayBuffer(blob))
.then(buff => {
var view = new Int8Array(buff); // not sure why this is needed
const buffer = Buffer.from(view);
// get coords here
const coords = 1000 + i // for purpose of demo
bufferMap.set(coords, buffer)
})
})
.then(_ => { // <- wait for previous to plete
console.log('bufferMap inside mand', bufferMap) // [[Entries]]
// 0: {0 => Uint8Array(27209)}
// 1: {1 => Uint8Array(1179)}
return bufferMap;
})
});
cy.visit('http://cartodb.github.io/Leaflet.CanvasLayer/example.html')
cy.get('canvas').renderCanvasMatrixToPng().then(bufferMap => {
console.log('bufferMap outside mand', bufferMap) // [[Entries]]
// 0: {1000 => Uint8Array(25218)}
// 1: {1001 => Uint8Array(1179)}
const asObject = Object.fromEntries(bufferMap);
cy.task('mergeImages', { buffers: asObject, savePath: 'cypress/snapshots' });
})
})
})
Task for demo
module.exports = (on, config) => {
...
on('task', {
mergeImages(options) {
const { buffers, savePath } = options;
console.log('buffers', buffers);
/* In terminal
buffers {
'1000': {
type: 'Buffer',
data: [
137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13,
... 33137 more items
]
},
'1001': {
type: 'Buffer',
data: [
137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13,
... 1079 more items
]
}
}
*/
return null;
}
})
}
Alternative mand (my preference)
Cypress.Commands.add('renderCanvasMatrixToPng', { prevSubject: true }, (subjects, savePath) => {
const bufferPromises = Array.from(subjects).map(canvas => {
return Cypress.Blob.canvasToBlob(canvas)
.then(blob => Cypress.Blob.blobToArrayBuffer(blob))
.then(buff => {
const view = new Int8Array(buff);
const buffer = Buffer.from(view);
return buffer;
})
})
return Promise.all(bufferPromises).then(buffers => {
const bufferMap = new Map();
buffers.forEach((buffer, i) => {
// get coords here
const coords = 1000 + i // for purpose of demo
bufferMap.set(coords, buffer)
})
return bufferMap;
})
});
So I found the solution!
Now it works pretty good for me. Code sample:
function convertCanvasMatrixToPictureCommand() {
Cypress.Commands.add('renderCanvasMatrixToPng', { prevSubject: true }, (subject, writeTo) => {
const imgArr = [];
cy.wrap(subject)
.each(canvas =>
new Cypress.Promise(resolve => {
Cypress.Blob.canvasToBlob(canvas.get(0))
.then(blob => Cypress.Blob.blobToArrayBuffer(blob))
.then(arrayBuffer => {
const coordinates = extract(canvas.attr('style'));
imgArr.push({ id: coordinates, buffer: arrayBuffer });
resolve(true);
});
}))
.then(() => {
cy.task('mergeImages', {
imageArrayBuffers: imgArr,
outputFolder: writeTo,
});
});
});
}