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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jspm_packages
docs/_site/*

# Generated site (MarkBind)
test/test_site/_site
test/functional/*/_site

# vscode configuration
.vscode/
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ language: node_js
node_js:
- '8'
before_install:
- chmod +x ./test/test_site/test.sh
- chmod +x ./test/functional/test.sh
cache:
directories:
- node_modules
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@
"lint": "./node_modules/.bin/eslint .",
"pretest": "npm run lint",
"pretestwin": "npm run lint",
"testwin": "jest && cd test/test_site && test.bat",
"test": "jest && cd test/test_site && ./test.sh",
"testwin": "jest && cd test/functional && test.bat",
"test": "jest && cd test/functional && ./test.sh",
"jest": "jest"
},
"jest": {
"testPathIgnorePatterns": [
"/node_modules/",
"test/test_site/"
"test/functional"
]
},
"devDependencies": {
Expand Down
21 changes: 21 additions & 0 deletions test/functional/test.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@ECHO off

set sites=test_site

for %%a in (%sites%) do (

echo(
echo Running %%a tests

node ../../index.js build %%a
Comment thread
jamos-tay marked this conversation as resolved.

node testUtil/test.js %%a

if errorlevel 1 (
echo Test %%a Failed
exit /b %errorlevel%
)
)

echo Test passed
exit /b %errorlevel%
26 changes: 26 additions & 0 deletions test/functional/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

declare -a sites=("test_site")

for site in "${sites[@]}"
do
# print site name
echo
echo "Running $site tests"

# build site
node ../../index.js build "$site"

# run our test script to compare html files
node testUtil/test.js "$site"

if [ $? -ne 0 ]
then
echo "Test result: $site FAILED"
exit 1
fi
done

# if there were no diffs
echo "Test result: PASSED"
exit 0
50 changes: 50 additions & 0 deletions test/functional/testUtil/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const diffHtml = require('./diffHtml');
const fs = require('fs');
const path = require('path');
const walkSync = require('walk-sync');

const _ = {};
_.isEqual = require('lodash/isEqual');

function readFileSync(...paths) {
return fs.readFileSync(path.resolve(...paths), 'utf8');
}

const sitePath = process.argv[2];
const expectedDirectory = path.join(sitePath, 'expected');
const actualDirectory = path.join(sitePath, '_site');

const expectedPaths = walkSync(expectedDirectory, { directories: false });
const actualPaths = walkSync(actualDirectory, { directories: false });

if (expectedPaths.length !== actualPaths.length) {
throw new Error('Unequal number of files');
}

for (let i = 0; i < expectedPaths.length; i += 1) {
const expectedFilePath = expectedPaths[i];
const actualFilePath = actualPaths[i];

if (expectedFilePath !== actualFilePath) {
throw new Error('Different files built');
}

const parsed = path.parse(actualFilePath);
if (parsed.ext === '.html') {
// compare html files
const expected = readFileSync(expectedDirectory, expectedFilePath);
const actual = readFileSync(actualDirectory, actualFilePath);
try {
diffHtml(expected, actual);
} catch (err) {
throw new Error(`${err.message} in ${expectedFilePath}`);
}
} else if (parsed.base === 'siteData.json') {
// compare site data
const expected = readFileSync(expectedDirectory, expectedFilePath);
const actual = readFileSync(actualDirectory, actualFilePath);
if (!_.isEqual(JSON.parse(expected), JSON.parse(actual))) {
throw new Error('Site data does not match with the expected file.');
}
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
105 changes: 105 additions & 0 deletions test/functional/test_site/testUtil/diffHtml.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
const jsdiff = require('diff');

/**
* Checks if fragment ends with an unclosed path
* true: src="
* false: src=""
* src="..."
*/
const endsWithUnclosedPath = (fragment) => {
for (let i = fragment.length - 1; i > 4; i -= 1) {
if (fragment[i] === '"') {
if (fragment.substring(i - 4, i) === 'src=' || fragment.substring(i - 5, i) === 'href=') {
return true;
}
return false;
}
}
return false;
};

/**
* Checks if the ending portion of the fragment is inside an html tag
* true: <tag src=".../
* <panel header="<a>link</a>" src=".../
* false: <text> src="..
* <div/>
* <panel header="<a>link</a>"> src="...
*/
const endsWithOpeningTag = (fragment) => {
let numUnmatchedClosingBracket = 0;
for (let i = fragment.length - 1; i >= 0; i -= 1) {
if (fragment[i] === '>') {
numUnmatchedClosingBracket += 1;
} else if (fragment[i] === '<') {
if (numUnmatchedClosingBracket === 0) {
return true;
}
numUnmatchedClosingBracket -= 1;
}
}
return false;
};

/**
* Checks if the start portion of the fragment closes a path
* Assumes that previous fragment was the start of or was within an unclosed path
* true: "
* path/to/file.jpg"
* file.jpg" <
* false: < src="...
* > "...
*/
const startsWithClosedPath = (fragment) => {
for (let i = 0; i <= fragment.length - 1; i += 1) {
if (fragment[i] === '<' || fragment[i] === '>') {
return false;
}
if (fragment[i] === '"') {
return true;
}
}
return false;
};

/**
* Checks if diff is a path separator character
*/
const isPathSeparatorDiff = diff => diff === '\\' || diff === '/';

/**
* Checks for any diffs between expected.html and actual.html
* @param {string} expected
* @param {string} actual
* @throws {Error} if any diffs that are not path separators are found
*/
const diffHtml = (expected, actual) => {
let insidePath = false;

const diff = jsdiff.diffChars(expected, actual);
const isDiff = part => part.added || part.removed;

// assumes no space between paths
const isClosedPath = fragment =>
insidePath
&& startsWithClosedPath(fragment);

diff.forEach((part) => {
if (isClosedPath(part.value)) {
insidePath = false;
}

if (endsWithUnclosedPath(part.value) && endsWithOpeningTag(part.value)) {
// Any diffs following this fragment will be diffs within a path
insidePath = true;
}

if (isDiff(part) && !insidePath) {
throw new Error(`Diff outside path!: '${part.value}'`);
} else if (isDiff(part) && !isPathSeparatorDiff(part.value)) {
throw new Error(`Diff in path!: '${part.value}'`);
}
});
};

module.exports = diffHtml;