html-inspector
Advanced tools
Comparing version
// Safe to assume arguments here | ||
var basePath = phantom.args[0], | ||
baseVersion = phantom.args[1], | ||
inspectLocation = phantom.args[2], | ||
configFile = phantom.args[3] | ||
var basePath = phantom.args[0] | ||
, inspectLocation = phantom.args[1] | ||
, configFile = phantom.args[2] | ||
var system = require('system'), | ||
page = require('webpage').create() | ||
var system = require('system') | ||
, page = require('webpage').create() | ||
var injectVersions = { | ||
full: [''], | ||
core: ['.core'], | ||
convention: ['.core', '.convention'], | ||
'best-practices': ['.core', '.best-practices'], | ||
validation: ['.core', '.validation'] | ||
page.onCallback = function(data) { | ||
if (data && data.sender && data.sender == "HTMLInspector") { | ||
console.log(data.message) | ||
} | ||
} | ||
page.onAlert = system.stdout.write | ||
page.onClosing = function() { | ||
phantom.exit() | ||
} | ||
page.onError = function(msg) { | ||
console.error(msg) | ||
phantom.exit() | ||
} | ||
page.onLoadFinished = function(status) { | ||
@@ -28,27 +32,30 @@ | ||
var hasInspectorScript = page.evaluate(function() { | ||
return 'HTMLInspector' in this | ||
return window.HTMLInspector | ||
}) | ||
if(!hasInspectorScript) { | ||
injectVersions[baseVersion].forEach(function(version) { | ||
page.injectJs(basePath + '/dist/html-inspector' + version + '.js') | ||
}) | ||
if (!hasInspectorScript) { | ||
page.injectJs(basePath + '/dist/html-inspector.js') | ||
} | ||
if(configFile) { | ||
page.evaluate(function() { | ||
HTMLInspector.defaults.onComplete = function(errors) { | ||
window.callPhantom({ | ||
sender: "HTMLInspector", | ||
message: errors.map(function(error) { | ||
return "[" + error.rule + "] " + error.message | ||
}).join("\n") | ||
}) | ||
window.close() | ||
} | ||
}) | ||
if (configFile) { | ||
page.injectJs(configFile) | ||
} else { | ||
page.evaluate(function() { | ||
HTMLInspector.inspect() | ||
}) | ||
} | ||
page.injectJs(basePath + '/bin/phantom-bridge.js') | ||
page.evaluate(function() { | ||
HTMLInspector.inspect({ | ||
onComplete: function onComplete(errors) { | ||
sendMessage('htmlinspector.complete', errors) | ||
} | ||
}) | ||
}) | ||
phantom.exit() | ||
} | ||
page.open(inspectLocation) |
{ | ||
"name": "html-inspector", | ||
"version": "0.4.1", | ||
"version": "0.5.0", | ||
"main": "dist/html-inspector.js", | ||
@@ -15,2 +15,2 @@ "ignore": [ | ||
] | ||
} | ||
} |
@@ -1,8 +0,11 @@ | ||
### 0.5.0 (Unreleased) | ||
### 0.5.0 (August 31, 2013) | ||
* Add `excludeRules` option. | ||
* Convert HTML Inspector to be built with Browserify. | ||
* Rename the `exclude` option to `excludeElements`. | ||
* Rename the `excludeSubtree` option to `excludeSubtrees`. | ||
* Remove the setConfig method as it was overwriting previous setConfigs if there were multiple calls. | ||
* Improve the CLI and allow for async error reporting via the config file. | ||
* Convert HTML Inspector to be built with Browserify and released as a UMD module. | ||
* Convert tests from Jasmine to Mocha, Sinon, and Chai. | ||
* Use Mout for JavaScript utility functions. | ||
* Abstract DOM utility functions to dom-utils package. | ||
* Remove the custom builds in favor better rule inclusion/exclusion options. | ||
@@ -9,0 +12,0 @@ ### 0.4.1 (July 10, 2013) |
{ | ||
"name": "html-inspector", | ||
"title": "HTML Inspector", | ||
"version": "0.4.1", | ||
"version": "0.5.0", | ||
"description": "HTML Inspector is a code quality tool to help you and your team write better markup. It's written in JavaScript and runs in the browser, so testing your HTML has never been easier.", | ||
@@ -6,0 +6,0 @@ "license": "MIT", |
112
README.md
@@ -10,7 +10,6 @@ # HTML Inspector | ||
5. [Overriding Rules Configurations](#overriding-rule-configurations) | ||
6. [Custom Builds](#custom-builds) | ||
7. [Browser Support](#browser-support) | ||
8. [Running the Tests](#running-the-tests) | ||
9. [Contributing](#contributing) | ||
10. [FAQs](#faqs) | ||
6. [Browser Support](#browser-support) | ||
7. [Running the Tests](#running-the-tests) | ||
8. [Contributing](#contributing) | ||
9. [FAQs](#faqs) | ||
@@ -31,5 +30,12 @@ HTML Inspector is a highly-customizable, code quality tool to help you (and your team) write better markup. It aims to find a balance between the uncompromisingly strict W3C validator and having absolutely no rules at all (the unfortunate reality for most of us). | ||
Alternatively, [Bower](https://github.com/bower/bower) users can install HTML Inspector with the following command: | ||
It can also be install via [NPM](https://npmjs.org/) or [Bower](https://github.com/bower/bower): | ||
```sh | ||
# NPM (for command line usage) | ||
npm install -g html-inspector | ||
# View the CLI options | ||
htmlinspector --help | ||
# Bower (for browser usage) | ||
bower install html-inspector | ||
@@ -58,6 +64,7 @@ ``` | ||
- **useRules**: (Array) a list of rule names to run when inspecting | ||
- **domRoot**: (selector | element) the DOM element to start traversing from | ||
- **exclude**: (selector | element | Array) any DOM element that matches the selector, element, or list of selectors/elements will be excluded from traversal (note: its descendants will still be traversed). | ||
- **excludeSubTree**: (selector } element | Array) the descendants of any DOM element that matches the selector, element, or list of selectors/elements will be excluded from traversal. | ||
- **useRules**: (Array) a list of rule names to run when inspecting. Defaults to running all rules not excluded via `excludeRules` | ||
- **excludeRules**: (Array) a list of rule names **not** to run when inspecting. If `useRules` and `excludeRules` are both set, the excluded rules are removed from the list of rules to use. | ||
- **excludeElements**: (selector | element | Array) any DOM element that matches the selector, element, or list of selectors/elements will be excluded from traversal (note: its descendants will still be traversed). | ||
- **excludeSubTrees**: (selector | element | Array) the descendants of any DOM element that matches the selector, element, or list of selectors/elements will be excluded from traversal. | ||
- **onComplete**: (Function) the callback to be invoked when the inspection is finished. The function is passed an array of errors that were reported by individual rules. | ||
@@ -69,6 +76,7 @@ | ||
config: { | ||
domRoot: "html", | ||
useRules: null, | ||
domRoot: "html", | ||
exclude: "svg", | ||
excludeSubTree: ["svg", "iframe"], | ||
excludeRules: null, | ||
excludeElements: "svg", | ||
excludeSubTrees: ["svg", "iframe"], | ||
onComplete: function(errors) { | ||
@@ -86,6 +94,5 @@ errors.forEach(function(error) { | ||
HTMLInspector.inspect({ | ||
useRules: ["some-rule-name", "some-other-rule-name"], | ||
domRoot: "body", | ||
exclude: "iframe", | ||
excludeSubTree: ["svg", "template"], | ||
excludeRules: ["some-rule-name", "some-other-rule-name"], | ||
excludeElements: ["svg", "iframe"], | ||
onComplete: function(errors) { | ||
@@ -120,2 +127,26 @@ errors.forEach(function(error) { | ||
Each rule is registered via a unique string identifier that can be used to include or exclude it at inspection time. | ||
Here is the full list of built in rules by their identifiers: | ||
```sh | ||
# validation rules | ||
validate-elements | ||
validate-element-location | ||
validate-attributes | ||
duplicate-ids | ||
unique-elements | ||
# best-practices | ||
inline-event-handlers | ||
script-placement | ||
unused-classes | ||
unnecessary-elements | ||
# convention | ||
bem-conventions | ||
``` | ||
The following is a more in-depth explanation of each rule: | ||
### Validation | ||
@@ -312,47 +343,2 @@ | ||
## Custom Builds | ||
HTML Inspector comes with a number of pre-built options to use directly in your projects. | ||
- **html-inspector.js**: The full HTML Inspector code with all built-in rules prepackaged. | ||
- **html-inspector.core.js**: The core library with none of the rules. | ||
- **html-inspector.validation.js**: A package containing only the validation rules | ||
- **html-inspector.best-practices.js**: A package containing only the best practice rules | ||
- **html-inspector.convention.js**: A package containing only the convention rules | ||
If the full version of HTML Inspector and all the built-in rules is too much, you can mix and match the core library with any combination of the packaged rule libraries as well as your own rules. | ||
The build options for each of these is as follows: | ||
```sh | ||
# build everything | ||
grunt | ||
# build the core library | ||
grunt dist:core | ||
# build the validation ruleset | ||
grunt dist:validation | ||
# build the best-practices ruleset | ||
grunt dist:best-practices | ||
# build the convention ruleset | ||
grunt dist:convention | ||
``` | ||
To alter the custom builds, simply add or remove files from the directories inside of `src/rules`. But keep in mind that rules can be excluded both at build time and at runtime. In other words, you don't need a custom build to exclude certain rules. You also don't need a custom build to add new rules. It's perfectly OK to add new rules directly to the HTML source as separate files. | ||
HTML Inspector uses [Grunt](http://gruntjs.com) which runs on [Node](http://nodejs.org/) to build and lint its source files as well as to run the [Jasmine](http://pivotal.github.io/jasmine/) tests. | ||
If you don't have Node, NPM, and Grunt installed, refer to their documentation for installation instructions. Once they're installed, you can install the rest of the dependencies with the following commands: | ||
```sh | ||
# Install Node packages | ||
npm install | ||
# Install script dependencies | ||
bower install | ||
``` | ||
## Browser Support | ||
@@ -373,3 +359,3 @@ | ||
If Grunt and all the dependencies are installed, you can run the Jasmine tests with the following command. | ||
If Grunt and all the dependencies are installed, you can run the tests with the following command. | ||
@@ -380,4 +366,6 @@ ```sh | ||
This creates a `spec-runner.html` file in the root directory and uses [PhantomJS](http://phantomjs.org/) to run the tests. If you prefer to run the tests in the browser, you can always fire up a local server and load `spec-runner.html` in the browser manually. | ||
HTML Inspector has two test suites, one that runs in pure Node and one that uses [Mocha](http://visionmedia.github.io/mocha/) and [PhantomJS](http://phantomjs.org/) because it needs a browser. | ||
If you want to run the browser tests in a real browser (instead of via PhantomJS) simply fire up a local server and load the `tests/html-inspector-test.html` file. Make sure to run `grunt test` beforehand as it builds the tests. | ||
## Contributing | ||
@@ -384,0 +372,0 @@ |
@@ -21,7 +21,12 @@ var Listener = require("./listener") | ||
*/ | ||
function setup(useRules, listener, reporter) { | ||
useRules = useRules == null | ||
function setup(listener, reporter, useRules, excludeRules) { | ||
var rules = useRules == null | ||
? Object.keys(HTMLInspector.rules) | ||
: useRules | ||
useRules.forEach(function(rule) { | ||
if (excludeRules) { | ||
rules = rules.filter(function(rule) { | ||
return excludeRules.indexOf(rule) < 0 | ||
}) | ||
} | ||
rules.forEach(function(rule) { | ||
if (HTMLInspector.rules[rule]) { | ||
@@ -38,3 +43,3 @@ HTMLInspector.rules[rule].func.call( | ||
function traverseDOM(node, listener, options) { | ||
function traverseDOM(listener, node, excludeElements, excludeSubTrees) { | ||
@@ -47,3 +52,3 @@ // only deal with element nodes | ||
// trigger events for this element unless it's been excluded | ||
if (!matches(node, options.exclude)) { | ||
if (!matches(node, excludeElements)) { | ||
listener.trigger("element", node, [node.nodeName.toLowerCase(), node]) | ||
@@ -62,5 +67,5 @@ if (node.id) { | ||
// recurse through the subtree unless it's been excluded | ||
if (!matches(node, options.excludeSubTree)) { | ||
if (!matches(node, excludeSubTrees)) { | ||
toArray(node.childNodes).forEach(function(node) { | ||
traverseDOM(node, listener, options) | ||
traverseDOM(listener, node, excludeElements, excludeSubTrees) | ||
}) | ||
@@ -70,15 +75,23 @@ } | ||
function processConfig(config) { | ||
function mergeOptions(options) { | ||
// allow config to be individual properties of the defaults object | ||
if (config) { | ||
if (typeof config == "string" || config.nodeType == 1) { | ||
config = { domRoot: config } | ||
} else if (Array.isArray(config)) { | ||
config = { useRules: config } | ||
} else if (typeof config == "function") { | ||
config = { onComplete: config } | ||
if (options) { | ||
if (typeof options == "string" || options.nodeType == 1) { | ||
options = { domRoot: options } | ||
} else if (Array.isArray(options)) { | ||
options = { useRules: options } | ||
} else if (typeof options == "function") { | ||
options = { onComplete: options } | ||
} | ||
} | ||
// merge config with the defaults | ||
return mixIn({}, HTMLInspector.config, config) | ||
// merge options with the defaults | ||
options = mixIn({}, HTMLInspector.defaults, options) | ||
// set the domRoot to an HTMLElement if it's not | ||
options.domRoot = typeof options.domRoot == "string" | ||
? document.querySelector(options.domRoot) | ||
: options.domRoot | ||
return options | ||
} | ||
@@ -111,3 +124,3 @@ | ||
) | ||
return "(can't display iframe with cross-origin source)" | ||
return "(can't display iframe with cross-origin source: " + el.src + ")" | ||
else | ||
@@ -123,6 +136,7 @@ return el | ||
defaults: { | ||
domRoot: "html", | ||
useRules: null, | ||
domRoot: "html", | ||
exclude: "svg", | ||
excludeSubTree: ["svg", "iframe"], | ||
excludeRules: null, | ||
excludeElements: "svg", | ||
excludeSubTrees: ["svg", "iframe"], | ||
onComplete: function(errors) { | ||
@@ -135,18 +149,2 @@ errors.forEach(function(error) { | ||
config: {}, | ||
setConfig: function(config) { | ||
// allow config to be individual properties of the defaults object | ||
if (config) { | ||
if (typeof config == "string" || config.nodeType == 1) { | ||
config = { domRoot: config } | ||
} else if (Array.isArray(config)) { | ||
config = { useRules: config } | ||
} else if (typeof config == "function") { | ||
config = { onComplete: config } | ||
} | ||
} | ||
mixIn(this.config, this.defaults, config) | ||
}, | ||
rules: new Rules(), | ||
@@ -156,19 +154,14 @@ | ||
inspect: function(config) { | ||
var domRoot | ||
inspect: function(options) { | ||
var config = mergeOptions(options) | ||
, listener = new Listener() | ||
, reporter = new Reporter() | ||
this.setConfig(config) | ||
domRoot = typeof this.config.domRoot == "string" | ||
? document.querySelector(this.config.domRoot) | ||
: this.config.domRoot | ||
setup(listener, reporter, config.useRules, config.excludeRules) | ||
setup(this.config.useRules, listener, reporter) | ||
listener.trigger("beforeInspect", config.domRoot) | ||
traverseDOM(listener, config.domRoot, config.excludeElements, config.excludeSubTrees) | ||
listener.trigger("afterInspect", config.domRoot) | ||
listener.trigger("beforeInspect", domRoot) | ||
traverseDOM(domRoot, listener, this.config) | ||
listener.trigger("afterInspect", domRoot) | ||
this.config.onComplete(reporter.getWarnings()) | ||
config.onComplete(reporter.getWarnings()) | ||
} | ||
@@ -175,0 +168,0 @@ } |
@@ -16,4 +16,3 @@ module.exports = { | ||
var css = HTMLInspector.modules.css | ||
, classes = css.getClassSelectors() | ||
var classes = this.modules.css.getClassSelectors() | ||
, foundIn = require("../../utils/string-matcher") | ||
@@ -20,0 +19,0 @@ |
@@ -7,3 +7,3 @@ module.exports = { | ||
var validation = HTMLInspector.modules.validation | ||
var validation = this.modules.validation | ||
@@ -10,0 +10,0 @@ listener.on("element", function(name) { |
@@ -7,3 +7,3 @@ module.exports = { | ||
var validation = HTMLInspector.modules.validation | ||
var validation = this.modules.validation | ||
@@ -10,0 +10,0 @@ listener.on("element", function(name) { |
@@ -31,43 +31,18 @@ describe("HTMLInspector", function() { | ||
describe(".setConfig", function() { | ||
describe(".inspect", function() { | ||
it("merges the passed config options with the defaults", function() { | ||
var useRules = ["foo", "bar"] | ||
, domRoot = "body" | ||
, exclude = "svg, iframe" | ||
, onComplete = function() {} | ||
HTMLInspector.setConfig({ | ||
useRules: useRules, | ||
domRoot: domRoot, | ||
exclude: exclude, | ||
onComplete: onComplete | ||
it("inspects the HTML starting from the specified domRoot", function() { | ||
var events = [] | ||
HTMLInspector.rules.add("traverse-test", function(listener, reporter) { | ||
listener.on("element", function(name) { | ||
events.push(name) | ||
}) | ||
}) | ||
expect(HTMLInspector.config.useRules).to.equal(useRules) | ||
expect(HTMLInspector.config.domRoot).to.equal(domRoot) | ||
expect(HTMLInspector.config.exclude).to.equal(exclude) | ||
expect(HTMLInspector.config.onComplete).to.equal(onComplete) | ||
expect(HTMLInspector.config.excludeSubTree).to.equal(HTMLInspector.defaults.excludeSubTree) | ||
HTMLInspector.inspect() | ||
expect(events[0]).to.equal("html") | ||
events = [] | ||
HTMLInspector.inspect({ domRoot: html }) | ||
expect(events[0]).to.equal("section") | ||
}) | ||
it("accepts a variety of options for the config paramter", function() { | ||
var div = document.createElement("div") | ||
, fn = function() { } | ||
// if it's an array, assume it's the useRules options | ||
HTMLInspector.setConfig(["dom"]) | ||
expect(HTMLInspector.config.useRules).to.deep.equal(["dom"]) | ||
// if it's a string, assume it's a selector for the domRoot option | ||
HTMLInspector.inspect("body") | ||
expect(HTMLInspector.config.domRoot).to.equal("body") | ||
// if it's a DOM element, assume it's the domRoot option | ||
HTMLInspector.inspect(div) | ||
expect(HTMLInspector.config.domRoot).to.equal(div) | ||
// if it's a function, assume it's the onComplete option | ||
HTMLInspector.inspect(fn) | ||
expect(HTMLInspector.config.onComplete).to.equal(fn) | ||
}) | ||
}) | ||
describe(".inspect", function() { | ||
it("only runs the specified rules (or all rules if none are specified)", function() { | ||
@@ -100,22 +75,28 @@ var rules = [] | ||
it("invokes the onComplete callback passing in an array of errors", function() { | ||
var log | ||
HTMLInspector.rules.add("one-two", function(listener, reporter) { | ||
reporter.warn("one-two", "This is the `one` error message", document) | ||
reporter.warn("one-two", "This is the `two` error message", document) | ||
it("excludes rules specifically mentioned in the `excludeRules` options", function() { | ||
var rules = [] | ||
HTMLInspector.rules.add("one", function(listener, reporter) { | ||
listener.on("beforeInspect", function(name) { rules.push("one") }) | ||
}) | ||
HTMLInspector.rules.add("two", function(listener, reporter) { | ||
listener.on("beforeInspect", function(name) { rules.push("two") }) | ||
}) | ||
HTMLInspector.rules.add("three", function(listener, reporter) { | ||
reporter.warn("three", "This is the `three` error message", document) | ||
listener.on("beforeInspect", function(name) { rules.push("three") }) | ||
}) | ||
HTMLInspector.inspect(function(errors) { | ||
log = errors | ||
HTMLInspector.inspect({ | ||
excludeRules: ["one", "two"] | ||
}) | ||
expect(log.length).to.equal(3) | ||
expect(log[0].message).to.equal("This is the `one` error message") | ||
expect(log[1].message).to.equal("This is the `two` error message") | ||
expect(log[2].message).to.equal("This is the `three` error message") | ||
expect(rules.length).to.equal(1) | ||
expect(rules[0]).to.equal("three") | ||
rules = [] | ||
HTMLInspector.inspect({ | ||
useRules: ["one", "two"], | ||
excludeRules: ["two"] | ||
}) | ||
expect(rules.length).to.equal(1) | ||
expect(rules[0]).to.equal("one") | ||
}) | ||
it("ignores elements matching the `exclude` config option", function() { | ||
it("ignores elements matching the `excludeElements` config option", function() { | ||
var events = [] | ||
@@ -129,3 +110,3 @@ HTMLInspector.rules.add("traverse-test", function(listener, reporter) { | ||
domRoot: html, | ||
exclude: ["h1", "p"] | ||
excludeElements: ["h1", "p"] | ||
}) | ||
@@ -136,3 +117,3 @@ expect(events).to.deep.equal(["section", "a", "blockquote", "em"]) | ||
domRoot: html, | ||
exclude: html.querySelector("blockquote") | ||
excludeElements: html.querySelector("blockquote") | ||
}) | ||
@@ -142,3 +123,3 @@ expect(events).to.deep.equal(["section", "h1", "p", "p", "a", "p", "p", "em"]) | ||
it("ignores elements that descend from the `excludeSubTree` config option", function() { | ||
it("ignores elements that descend from the `excludeSubTrees` config option", function() { | ||
var events = [] | ||
@@ -152,3 +133,3 @@ HTMLInspector.rules.add("traverse-test", function(listener, reporter) { | ||
domRoot: html, | ||
excludeSubTree: "p" | ||
excludeSubTrees: "p" | ||
}) | ||
@@ -159,3 +140,3 @@ expect(events).to.deep.equal(["section", "h1", "p", "p", "blockquote", "p", "p"]) | ||
domRoot: html, | ||
excludeSubTree: [html.querySelector("p:not(.first)"), html.querySelector("blockquote")] | ||
excludeSubTrees: [html.querySelector("p:not(.first)"), html.querySelector("blockquote")] | ||
}) | ||
@@ -165,14 +146,61 @@ expect(events).to.deep.equal(["section", "h1", "p", "p", "blockquote"]) | ||
it("inspects the HTML starting from the specified domRoot", function() { | ||
var events = [] | ||
HTMLInspector.rules.add("traverse-test", function(listener, reporter) { | ||
it("invokes the onComplete callback passing in an array of errors", function() { | ||
var log | ||
HTMLInspector.rules.add("one-two", function(listener, reporter) { | ||
reporter.warn("one-two", "This is the `one` error message", document) | ||
reporter.warn("one-two", "This is the `two` error message", document) | ||
}) | ||
HTMLInspector.rules.add("three", function(listener, reporter) { | ||
reporter.warn("three", "This is the `three` error message", document) | ||
}) | ||
HTMLInspector.inspect(function(errors) { | ||
log = errors | ||
}) | ||
expect(log.length).to.equal(3) | ||
expect(log[0].message).to.equal("This is the `one` error message") | ||
expect(log[1].message).to.equal("This is the `two` error message") | ||
expect(log[2].message).to.equal("This is the `three` error message") | ||
}) | ||
it("accepts a variety of types for the options paramter", function() { | ||
var log = [] | ||
, div = document.createElement("div") | ||
HTMLInspector.rules.add("dom", function(listener, reporter) { | ||
listener.on("element", function(name) { | ||
events.push(name) | ||
log.push(this) | ||
}) | ||
}) | ||
HTMLInspector.inspect() | ||
expect(events[0]).to.equal("html") | ||
events = [] | ||
HTMLInspector.inspect({ domRoot: html }) | ||
expect(events[0]).to.equal("section") | ||
HTMLInspector.rules.add("rules", function() { | ||
log.push("rules") | ||
}) | ||
// if it's an object, assume it's the full config object | ||
HTMLInspector.inspect({ | ||
useRules: ["dom"], | ||
domRoot: parseHTML("<p>foobar</p>"), | ||
onComplete: function(errors) { | ||
log.push("done") | ||
} | ||
}) | ||
expect(log.length).to.equal(2) | ||
expect(log[0].innerHTML).to.equal("foobar") | ||
expect(log[1]).to.equal("done") | ||
log = [] | ||
// if it's an array, assume it's a list of rules | ||
HTMLInspector.inspect(["dom"]) | ||
expect(log.indexOf("rules")).to.equal(-1) | ||
log = [] | ||
// if it's a string, assume it's a selector | ||
HTMLInspector.inspect("body") | ||
expect(log[1]).to.equal(document.body) | ||
log = [] | ||
// if it's a DOM element, assume it's the domRoot | ||
HTMLInspector.inspect(div) | ||
expect(log[1]).to.equal(div) | ||
log = [] | ||
// if it's a function, assume it's complete | ||
HTMLInspector.inspect(function(errors) { | ||
log = "func" | ||
}) | ||
expect(log).to.equal("func") | ||
}) | ||
@@ -337,3 +365,3 @@ | ||
expect(console.warn.callCount).to.equal(3) | ||
expect(console.warn.getCall(1).args[1]).to.equal("(can't display iframe with cross-origin source)") | ||
expect(console.warn.getCall(1).args[1]).to.equal("(can't display iframe with cross-origin source: http://example.com/)") | ||
expect(console.warn.getCall(2).args[1]).to.equal(iframe2) | ||
@@ -340,0 +368,0 @@ console.warn.restore() |
@@ -31,43 +31,18 @@ describe("HTMLInspector", function() { | ||
describe(".setConfig", function() { | ||
describe(".inspect", function() { | ||
it("merges the passed config options with the defaults", function() { | ||
var useRules = ["foo", "bar"] | ||
, domRoot = "body" | ||
, exclude = "svg, iframe" | ||
, onComplete = function() {} | ||
HTMLInspector.setConfig({ | ||
useRules: useRules, | ||
domRoot: domRoot, | ||
exclude: exclude, | ||
onComplete: onComplete | ||
it("inspects the HTML starting from the specified domRoot", function() { | ||
var events = [] | ||
HTMLInspector.rules.add("traverse-test", function(listener, reporter) { | ||
listener.on("element", function(name) { | ||
events.push(name) | ||
}) | ||
}) | ||
expect(HTMLInspector.config.useRules).to.equal(useRules) | ||
expect(HTMLInspector.config.domRoot).to.equal(domRoot) | ||
expect(HTMLInspector.config.exclude).to.equal(exclude) | ||
expect(HTMLInspector.config.onComplete).to.equal(onComplete) | ||
expect(HTMLInspector.config.excludeSubTree).to.equal(HTMLInspector.defaults.excludeSubTree) | ||
HTMLInspector.inspect() | ||
expect(events[0]).to.equal("html") | ||
events = [] | ||
HTMLInspector.inspect({ domRoot: html }) | ||
expect(events[0]).to.equal("section") | ||
}) | ||
it("accepts a variety of options for the config paramter", function() { | ||
var div = document.createElement("div") | ||
, fn = function() { } | ||
// if it's an array, assume it's the useRules options | ||
HTMLInspector.setConfig(["dom"]) | ||
expect(HTMLInspector.config.useRules).to.deep.equal(["dom"]) | ||
// if it's a string, assume it's a selector for the domRoot option | ||
HTMLInspector.inspect("body") | ||
expect(HTMLInspector.config.domRoot).to.equal("body") | ||
// if it's a DOM element, assume it's the domRoot option | ||
HTMLInspector.inspect(div) | ||
expect(HTMLInspector.config.domRoot).to.equal(div) | ||
// if it's a function, assume it's the onComplete option | ||
HTMLInspector.inspect(fn) | ||
expect(HTMLInspector.config.onComplete).to.equal(fn) | ||
}) | ||
}) | ||
describe(".inspect", function() { | ||
it("only runs the specified rules (or all rules if none are specified)", function() { | ||
@@ -100,22 +75,28 @@ var rules = [] | ||
it("invokes the onComplete callback passing in an array of errors", function() { | ||
var log | ||
HTMLInspector.rules.add("one-two", function(listener, reporter) { | ||
reporter.warn("one-two", "This is the `one` error message", document) | ||
reporter.warn("one-two", "This is the `two` error message", document) | ||
it("excludes rules specifically mentioned in the `excludeRules` options", function() { | ||
var rules = [] | ||
HTMLInspector.rules.add("one", function(listener, reporter) { | ||
listener.on("beforeInspect", function(name) { rules.push("one") }) | ||
}) | ||
HTMLInspector.rules.add("two", function(listener, reporter) { | ||
listener.on("beforeInspect", function(name) { rules.push("two") }) | ||
}) | ||
HTMLInspector.rules.add("three", function(listener, reporter) { | ||
reporter.warn("three", "This is the `three` error message", document) | ||
listener.on("beforeInspect", function(name) { rules.push("three") }) | ||
}) | ||
HTMLInspector.inspect(function(errors) { | ||
log = errors | ||
HTMLInspector.inspect({ | ||
excludeRules: ["one", "two"] | ||
}) | ||
expect(log.length).to.equal(3) | ||
expect(log[0].message).to.equal("This is the `one` error message") | ||
expect(log[1].message).to.equal("This is the `two` error message") | ||
expect(log[2].message).to.equal("This is the `three` error message") | ||
expect(rules.length).to.equal(1) | ||
expect(rules[0]).to.equal("three") | ||
rules = [] | ||
HTMLInspector.inspect({ | ||
useRules: ["one", "two"], | ||
excludeRules: ["two"] | ||
}) | ||
expect(rules.length).to.equal(1) | ||
expect(rules[0]).to.equal("one") | ||
}) | ||
it("ignores elements matching the `exclude` config option", function() { | ||
it("ignores elements matching the `excludeElements` config option", function() { | ||
var events = [] | ||
@@ -129,3 +110,3 @@ HTMLInspector.rules.add("traverse-test", function(listener, reporter) { | ||
domRoot: html, | ||
exclude: ["h1", "p"] | ||
excludeElements: ["h1", "p"] | ||
}) | ||
@@ -136,3 +117,3 @@ expect(events).to.deep.equal(["section", "a", "blockquote", "em"]) | ||
domRoot: html, | ||
exclude: html.querySelector("blockquote") | ||
excludeElements: html.querySelector("blockquote") | ||
}) | ||
@@ -142,3 +123,3 @@ expect(events).to.deep.equal(["section", "h1", "p", "p", "a", "p", "p", "em"]) | ||
it("ignores elements that descend from the `excludeSubTree` config option", function() { | ||
it("ignores elements that descend from the `excludeSubTrees` config option", function() { | ||
var events = [] | ||
@@ -152,3 +133,3 @@ HTMLInspector.rules.add("traverse-test", function(listener, reporter) { | ||
domRoot: html, | ||
excludeSubTree: "p" | ||
excludeSubTrees: "p" | ||
}) | ||
@@ -159,3 +140,3 @@ expect(events).to.deep.equal(["section", "h1", "p", "p", "blockquote", "p", "p"]) | ||
domRoot: html, | ||
excludeSubTree: [html.querySelector("p:not(.first)"), html.querySelector("blockquote")] | ||
excludeSubTrees: [html.querySelector("p:not(.first)"), html.querySelector("blockquote")] | ||
}) | ||
@@ -165,14 +146,61 @@ expect(events).to.deep.equal(["section", "h1", "p", "p", "blockquote"]) | ||
it("inspects the HTML starting from the specified domRoot", function() { | ||
var events = [] | ||
HTMLInspector.rules.add("traverse-test", function(listener, reporter) { | ||
it("invokes the onComplete callback passing in an array of errors", function() { | ||
var log | ||
HTMLInspector.rules.add("one-two", function(listener, reporter) { | ||
reporter.warn("one-two", "This is the `one` error message", document) | ||
reporter.warn("one-two", "This is the `two` error message", document) | ||
}) | ||
HTMLInspector.rules.add("three", function(listener, reporter) { | ||
reporter.warn("three", "This is the `three` error message", document) | ||
}) | ||
HTMLInspector.inspect(function(errors) { | ||
log = errors | ||
}) | ||
expect(log.length).to.equal(3) | ||
expect(log[0].message).to.equal("This is the `one` error message") | ||
expect(log[1].message).to.equal("This is the `two` error message") | ||
expect(log[2].message).to.equal("This is the `three` error message") | ||
}) | ||
it("accepts a variety of types for the options paramter", function() { | ||
var log = [] | ||
, div = document.createElement("div") | ||
HTMLInspector.rules.add("dom", function(listener, reporter) { | ||
listener.on("element", function(name) { | ||
events.push(name) | ||
log.push(this) | ||
}) | ||
}) | ||
HTMLInspector.inspect() | ||
expect(events[0]).to.equal("html") | ||
events = [] | ||
HTMLInspector.inspect({ domRoot: html }) | ||
expect(events[0]).to.equal("section") | ||
HTMLInspector.rules.add("rules", function() { | ||
log.push("rules") | ||
}) | ||
// if it's an object, assume it's the full config object | ||
HTMLInspector.inspect({ | ||
useRules: ["dom"], | ||
domRoot: parseHTML("<p>foobar</p>"), | ||
onComplete: function(errors) { | ||
log.push("done") | ||
} | ||
}) | ||
expect(log.length).to.equal(2) | ||
expect(log[0].innerHTML).to.equal("foobar") | ||
expect(log[1]).to.equal("done") | ||
log = [] | ||
// if it's an array, assume it's a list of rules | ||
HTMLInspector.inspect(["dom"]) | ||
expect(log.indexOf("rules")).to.equal(-1) | ||
log = [] | ||
// if it's a string, assume it's a selector | ||
HTMLInspector.inspect("body") | ||
expect(log[1]).to.equal(document.body) | ||
log = [] | ||
// if it's a DOM element, assume it's the domRoot | ||
HTMLInspector.inspect(div) | ||
expect(log[1]).to.equal(div) | ||
log = [] | ||
// if it's a function, assume it's complete | ||
HTMLInspector.inspect(function(errors) { | ||
log = "func" | ||
}) | ||
expect(log).to.equal("func") | ||
}) | ||
@@ -337,3 +365,3 @@ | ||
expect(console.warn.callCount).to.equal(3) | ||
expect(console.warn.getCall(1).args[1]).to.equal("(can't display iframe with cross-origin source)") | ||
expect(console.warn.getCall(1).args[1]).to.equal("(can't display iframe with cross-origin source: http://example.com/)") | ||
expect(console.warn.getCall(2).args[1]).to.equal(iframe2) | ||
@@ -340,0 +368,0 @@ console.warn.restore() |
Sorry, the diff of this file is too big to display
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
2
-50%0
-100%351972
-17.32%61
-6.15%6833
-21.27%372
-3.12%