| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| |
| const fs = require('fs'); |
| const path = require('path'); |
| const util = require('util'); |
| const { RESULT_FILE_NAME } = require('./store'); |
| |
| const readFileAsync = util.promisify(fs.readFile); |
| |
| function resolveImagePath(imageUrl) { |
| if (!imageUrl) { |
| return ''; |
| } |
| |
| // The original image path is relative to the client. |
| return imageUrl.replace(/\.\.\/tmp/g, './tmp'); |
| } |
| |
| async function inlineImage(imageUrl) { |
| if (!imageUrl) { |
| return ''; |
| } |
| try { |
| let fullPath = path.join(__dirname, resolveImagePath(imageUrl)); |
| // let img = await jimp.read(fullPath); |
| // img.quality(70); |
| // return img.getBase64Async('image/jpeg'); |
| let imgBuffer = await readFileAsync(fullPath); |
| return 'data:image/webp;base64,' + imgBuffer.toString('base64'); |
| } |
| catch (e) { |
| console.error(e); |
| return ''; |
| } |
| |
| } |
| |
| async function genDetail(test) { |
| let shotDetail = ''; |
| let prevShotDesc = ''; |
| let failed = 0; |
| for (let shot of test.results) { |
| if (shot.diffRatio < 0.001) { |
| continue; |
| } |
| failed++; |
| |
| // Batch same description shot |
| if (shot.desc !== prevShotDesc) { |
| shotDetail += `\n#### ${shot.desc}`; |
| prevShotDesc = shot.desc; |
| } |
| |
| let [expectedUrl, actualUrl, diffUrl] = await Promise.all([ |
| inlineImage(shot.expected), |
| inlineImage(shot.actual), |
| inlineImage(shot.diff) |
| // resolveImagePath(shot.expected), |
| // resolveImagePath(shot.actual), |
| // resolveImagePath(shot.diff) |
| ]); |
| shotDetail += ` |
| <div style="margin-top:10px"> |
| <figure style="width: 30%;display:inline-block;margin:0 10px;"> |
| <img src="${expectedUrl}" style="width:100%" /> |
| <figcaption>Expected ${test.expectedVersion}</figcaption> |
| </figure> |
| <figure style="width: 30%;display:inline-block;margin:0 10px;"> |
| <img src="${actualUrl}" style="width:100%" /> |
| <figcaption>Actual ${test.actualVersion}</figcaption> |
| </figure> |
| <figure style="width: 30%;display:inline-block;margin:0 10px;"> |
| <img src="${diffUrl}" style="width:100%" /> |
| <figcaption>Diff(${shot.diffRatio && shot.diffRatio.toFixed(3)})</figcaption> |
| </figure> |
| </div> |
| `; |
| } |
| return { |
| content: shotDetail, |
| failed, |
| total: test.results.length |
| }; |
| } |
| |
| module.exports = async function(testDir) { |
| let sections = []; |
| |
| let failedTest = 0; |
| |
| const tests = JSON.parse(fs.readFileSync( |
| path.join(testDir, RESULT_FILE_NAME), 'utf-8' |
| )); |
| |
| for (let test of tests) { |
| let detail = await genDetail(test); |
| |
| if (detail.failed > 0) { |
| failedTest++; |
| let title = `${failedTest}. ${test.name} (Failed ${detail.failed} / ${detail.total})`; |
| console.log(title); |
| |
| let sectionText = ` |
| <div style="margin-top: 100px;height: 20px;border-top: 1px solid #aaa"></div> |
| <a id="${test.name}"></a> |
| |
| <h2>${title}</h2> |
| |
| ${detail.content} |
| `; |
| |
| sections.push({ |
| content: sectionText, |
| title, |
| id: test.name |
| }); |
| } |
| } |
| |
| let htmlText = '<h1> Visual Regression Test Report</h1>\n'; |
| htmlText += ` |
| <p>Total: ${tests.length}</p> |
| <p>Failed: ${failedTest}</p> |
| `; |
| htmlText += '<ul>\n' + sections.map(section => { |
| return `<li><a href="${section.id}">${section.title}</a></li>`; |
| }).join('\n') + '</ul>'; |
| htmlText += sections.map(section => section.content).join('\n\n'); |
| |
| const file = path.join(testDir, 'report.html'); |
| fs.writeFileSync(file, htmlText, 'utf-8'); |
| return file; |
| } |
| |