Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 52 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
"eslint-config-airbnb-base": "^14.0.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-lodash": "^6.0.0",
"istextorbinary": "^3.3.0",
"jest": "^25.1.0",
"memfs": "^3.0.1",
"stylelint": "^12.0.0",
Expand Down
23 changes: 23 additions & 0 deletions test/functional/testUtil/diffChars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const jsdiff = require('diff');
const DiffPrinter = require('./diffPrinter');

/**
* Checks for any diffs between expected.html and actual.html,
* then prints the differences.
* @param {string} expected
* @param {string} actual
* @param {string} filePathName
* @returns {boolean} if diff was found
*/
const diffCharsAndPrint = (expected, actual, filePathName) => {
const diffParts = jsdiff.diffChars(expected, actual);
const isDiff = part => part.added || part.removed;
const hasDiff = diffParts.some(isDiff);
if (hasDiff) {
DiffPrinter.printDiffFoundMessage(filePathName);
DiffPrinter.printDiff(diffParts);
}
return hasDiff;
};

module.exports = diffCharsAndPrint;
25 changes: 0 additions & 25 deletions test/functional/testUtil/diffHtml.js

This file was deleted.

111 changes: 63 additions & 48 deletions test/functional/testUtil/diffPrinter.js
Original file line number Diff line number Diff line change
@@ -1,61 +1,73 @@
const ANSI_RED = '\u001B[31m';
const ANSI_GREEN = '\u001B[32m';
const ANSI_GREY = '\u001B[90m';
const ANSI_RESET = '\u001B[0m';
const chalk = require('chalk');

const EMPTY_LINE = '|-------------------empty-line-------------------|';
const CONSECUTIVE_NEWLINE_REGEX = new RegExp('\\n{2,}', 'g');
const WHITESPACE_REGEX = new RegExp('\\s+', 'g');

class DiffPrinter {
/**
* Prints line of text in colour provided
* @param {string} text text to print, default: no text
* @param {string} colour colour of text, default: no colour
* Replaces all newlines except the first with EMPTY_LINE.
*/
static printLine(text = '', colour = 'none') {
let ansiEscCode = '';
switch (colour) {
case 'red':
ansiEscCode = ANSI_RED;
break;
case 'green':
ansiEscCode = ANSI_GREEN;
break;
case 'grey':
ansiEscCode = ANSI_GREY;
break;
default:
ansiEscCode = '';
break;
static prependNewLines(match) {
return `\n${match.replace('\n', '').split('\n').join(`${EMPTY_LINE}\n`)}`;
}

static formatNewLines(value, prevVal, nextVal) {
let printValue;
printValue = value.replace(CONSECUTIVE_NEWLINE_REGEX, this.prependNewLines);

/**
* Replace consecutive newlines between current value and adjacent values
*/

const currentValStartsWithNewLine = printValue.startsWith('\n');
const prevValEndsWithNewLine = prevVal && prevVal.endsWith('\n');
if (currentValStartsWithNewLine && prevValEndsWithNewLine) {
printValue = EMPTY_LINE + printValue;
}
process.stderr.write(`${ansiEscCode}${text}${ANSI_RESET}\n`);

const currentValEndsWithNewLine = printValue.endsWith('\n');
const nextValStartsWithNewLine = nextVal && nextVal.startsWith('\n');
if (currentValEndsWithNewLine && nextValStartsWithNewLine) {
printValue += EMPTY_LINE;
}

return printValue;
}

/**
* Splits and combines change objects such that their value contains a single line
* Also adds ANSI Escape Codes for diffs and unchanged lines
* @param {Array} parts array of change objects returned by jsdiff#diffWords
* @param {Array} diffObjects array of change objects returned by jsdiff#diffWords
* @returns {Array} change objects where their value contains a single line
*/
static generateLineParts(parts) {
let lineParts = [{ value: '' }];
parts.forEach(({ value, added, removed }) => {
let lines = value.split(/\n/);
let asciEscCode = ANSI_GREY;
if (added) asciEscCode = ANSI_GREEN;
else if (removed) asciEscCode = ANSI_RED;
lines = lines.map(line => ({
value: asciEscCode + line + ANSI_RESET,
diff: added || removed,
}));

if (lines.length) {
const prevPart = lineParts.pop();
lines[0] = {
value: prevPart.value + lines[0].value,
diff: lines[0].diff || prevPart.diff,
};
static generateLineParts(diffObjects) {
const parts = [];
diffObjects.forEach(({ value, added, removed }, i) => {
let printValue = value;
if (added || removed) {
printValue = this.formatNewLines(printValue,
diffObjects[i - 1] && diffObjects[i - 1].value,
diffObjects[i + 1] && diffObjects[i - 1].value);
printValue = added
? chalk.green(printValue.replace(WHITESPACE_REGEX,
match => chalk.bgGreenBright(match)))
: chalk.red(printValue.replace(WHITESPACE_REGEX,
match => chalk.bgRedBright(match)));
parts.push({
value: printValue,
diff: true,
});
} else {
// Split into lines only when it is untouched to avoid printing too much of the untouched areas
const lineParts = printValue.split('\n').map((line, index, lines) => ({
value: (index === lines.length - 1) ? chalk.grey(line) : `${chalk.grey(line)}\n`,
diff: false,
}));
parts.push(...lineParts);
}
lineParts = lineParts.concat(lines);
});
return lineParts;
return parts;
}

/**
Expand All @@ -75,6 +87,11 @@ class DiffPrinter {
});
}

static printDiffFoundMessage(filePath) {
const message = chalk.grey(`\n-------------------------------------\nDiff found in ${filePath}\n\n`);
process.stderr.write(message);
}

/**
* Prints value in line objects that are set for printing
* If there is a gap between lines, print ellipsis
Expand All @@ -86,11 +103,9 @@ class DiffPrinter {
const prevPart = lineParts[i - 1];
if (linePart.toPrint) {
if (prevPart && !prevPart.toPrint) {
this.printLine();
this.printLine('...', 'grey');
this.printLine();
process.stderr.write(chalk.grey('\n...\n'));
}
this.printLine(linePart.value, 'none'); // already has ANSI Escape Code
process.stderr.write(linePart.value);
}
});
}
Expand Down
Loading