DEV Community

Will Drygla
Will Drygla

Posted on

Uploading screenshots to Azure tests

I wanna share a solution that I have developed to improve my debugging with Cypress and Azure. Cypress takes screenshots of test failures, which give us a lot of context about the failure, but, I didn’t find a way to visualize these screenshots with Azure. So, I looked over the internet and found some articles, I took this as a base, and developed a custom solution. I will bring here step-by-step how I do it.

Basically:

  1. Grab all Cypress screenshots and simplify they name
  2. Get all test runs for that release
  3. Then Get all failed tests to that release
  4. For each test find a matching screenshot and upload it Let's see:

1- We need to get all screenshots and save its path on a variable to use later, here, comes our first problem, depending of how the test fails, the screenshot name changes, appears a 'before each', 'after each', to make this work, I made a function to simplify the name, it receives the full path, remove unnecessary data, and save to a pathMap, then, after we use the same function to simplify the test case name and look for a match:

function simplifyName(filename: string): string {
return filename
.replace(/ --/g, '')
.replace(/"/g, '')
.replace(/ \(failed\)\.png/g, '')
.replace(/before each hook/g, '')
.replace(/after each hook/g, '')
.replace(/for/g, '')
.replace(/ /g, '');
}

async function collectPngFiles(directory: string, pathMap: Map<string, string>): Promise<void> {
const entries = await fs.readdir(directory, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(directory, entry.name);
if (entry.isDirectory()) {
await collectPngFiles(fullPath, pathMap);
} else if (entry.isFile() && entry.name.endsWith('.png')) {
const simplifiedName = simplifyName(entry.name);
pathMap.set(simplifiedName, fullPath);
}
}
}

These two functions save the simplified name and its corresponding full path to a variable pathMap.

2- Now, we need to get all failed tests on the release of Azure. To this, I make a get on Azure, that returns all test runs from that release, with that in hand, for each test run, I make a new get, but this time, only searching for failed tests. Then, for each failed test, I apply the same algorithm to simplify its name, then we need to check if there is a screenshot who matches the test case name on the pathMap .

const testRunResponse = await axios.get(testRunUrl, {
headers: getHeaders()
})
const listOfRuns = testRunResponse.data.value
for (const testRun of listOfRuns[]) {
const testResultsUrl = ${teamFoundationCollectionUri}${teamProjectId}/_apis/test/runs/${testRun.id}/results?api-version=5.1&outcomes=Failed;
const testResultsResponse = await axios.get(testResultsUrl, { headers: getHeaders() });
for (const testResult of testResultsResponse.data.value) {
let testCaseName = simplifyName(testResult.testCase.name);
const testResultId = testResult.id;
const screenshotPath = pathMap.get(testCaseName);

3- When we find a match, between the screenshots taken by Cypress and failed tests on Azure, we need to upload it to Azure on that test run, to be available to check on azure:

if (screenshotPath) {
const screenshotFilenameWithoutPath = path.basename(screenshotPath);
const createTestResultsAttachmentUrl = ${teamFoundationCollectionUri}${teamProjectId}/_apis/test/runs/${testRun.id}/results/${testResultId}/attachments?api-version=5.1-preview.1;
const base64string = await fs.readFile(screenshotPath, { encoding: 'base64' });
const jsonBody = {
fileName: screenshotFilenameWithoutPath,
comment: 'Attaching screenshot',
attachmentType: 'GeneralAttachment',
stream: base64string
};
const response = await axios.post(createTestResultsAttachmentUrl, jsonBody, {
headers: {
Authorization: Basic ${btoa(:${personalAccessToken}
)},
'Content-Type': 'application/json'
}
});

Then we only need to deal with Azure response.

This is a Typescript script, that is the same of the tests, it runs after tests on Azure. I made this a few months ago, and this is really helping me debug, since I don’t need to run the test locally again to see what is wrong, the context given by the screenshots really helps the understanding.

I hope it helps somebody with a similar problem!

Screenshot that show how the uploaded screenshot of cypress appears on the Azure test page

Top comments (0)