From 9ac1b334ae0869d1ae3b9fdcc6334b0e3463c5c4 Mon Sep 17 00:00:00 2001
From: Paul Grenier <pgrenier@gmail.com>
Date: Wed, 2 Oct 2019 15:03:07 -0400
Subject: [PATCH] chore: ensures axe Pro api

---
 test/integration/api/external/external.html |  28 +++
 test/integration/api/external/external.js   | 218 ++++++++++++++++++++
 2 files changed, 246 insertions(+)
 create mode 100644 test/integration/api/external/external.html
 create mode 100644 test/integration/api/external/external.js

diff --git a/test/integration/api/external/external.html b/test/integration/api/external/external.html
new file mode 100644
index 0000000000..d3bd3f771c
--- /dev/null
+++ b/test/integration/api/external/external.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML+ARIA 1.0//EN" "http://www.w3.org/WAI/ARIA/schemata/html4-aria-1.dtd">
+<html lang="en">
+	<head>
+		<title>External API Test</title>
+
+		<link
+			rel="stylesheet"
+			type="text/css"
+			href="/node_modules/mocha/mocha.css"
+		/>
+		<script src="/node_modules/mocha/mocha.js"></script>
+		<script src="/node_modules/chai/chai.js"></script>
+		<script src="/axe.js"></script>
+		<script>
+			mocha.setup({
+				timeout: 10000,
+				ui: 'bdd'
+			});
+			var assert = chai.assert;
+		</script>
+		<script src="/test/integration/no-ui-reporter.js"></script>
+	</head>
+	<body>
+		<div id="mocha"></div>
+		<script src="external.js"></script>
+		<script src="/test/integration/adapter.js"></script>
+	</body>
+</html>
diff --git a/test/integration/api/external/external.js b/test/integration/api/external/external.js
new file mode 100644
index 0000000000..1698a3f626
--- /dev/null
+++ b/test/integration/api/external/external.js
@@ -0,0 +1,218 @@
+// describes the API used by axe Pro
+describe('external API', function() {
+	'use strict';
+
+	afterEach(function() {
+		// setup _tree as needed, always reset
+		axe._tree = null;
+	});
+
+	describe('axe.commons.text.sanitize', function() {
+		it('typeof fn', function() {
+			assert.isFunction(axe.commons.text.sanitize);
+		});
+		it('str => str', function() {
+			assert.isString(axe.commons.text.sanitize(''));
+			assert.isString(axe.commons.text.sanitize('not empty'));
+		});
+	});
+
+	describe('axe.utils.getBaseLang', function() {
+		it('typeof fn', function() {
+			assert.isFunction(axe.utils.getBaseLang);
+		});
+		it('str => str', function() {
+			assert.isString(axe.utils.getBaseLang(''));
+			assert.isString(axe.utils.getBaseLang('not empty'));
+		});
+	});
+
+	describe('axe.utils.validLangs', function() {
+		it('typeof fn', function() {
+			assert.isFunction(axe.utils.validLangs);
+		});
+		it('any => arr', function() {
+			assert.isArray(axe.utils.validLangs());
+			assert.isArray(axe.utils.validLangs(document));
+			assert.isArray(axe.utils.validLangs({}));
+		});
+	});
+
+	describe('axe.commons.dom.isVisible', function() {
+		it('typeof fn', function() {
+			assert.isFunction(axe.commons.dom.isVisible);
+		});
+		it('el => bool', function() {
+			assert.isBoolean(axe.commons.dom.isVisible(randomNodeInTree(isElement)));
+		});
+	});
+
+	describe('axe.commons.aria.implicitRole', function() {
+		it('typeof fn', function() {
+			assert.isFunction(axe.commons.aria.implicitRole);
+		});
+		it('el => str|null', function() {
+			var implicitRolesOrNull = Object.entries(
+				axe.commons.aria.lookupTable.role
+			).reduce(
+				function(roles, entry) {
+					var role = entry[0];
+					var val = entry[1];
+					if (val.implicit) {
+						roles.push(role);
+					}
+					return roles;
+				},
+				[null]
+			);
+			var role = axe.commons.aria.implicitRole(randomNodeInTree());
+			assert.oneOf(role, implicitRolesOrNull);
+		});
+	});
+
+	describe('axe.commons.aria.lookupTable.role', function() {
+		it('typeof obj', function() {
+			assert.isObject(axe.commons.aria.lookupTable.role);
+		});
+		it('str <=> str (role.type)', function() {
+			var keys = Object.keys(axe.commons.aria.lookupTable.role);
+			var types = Object.values(axe.commons.aria.lookupTable.role).map(function(
+				role
+			) {
+				return role.type;
+			});
+			keys.forEach(assert.isString);
+			types.forEach(assert.isString);
+		});
+	});
+
+	describe('axe.utils.getFlattenedTree', function() {
+		it('typeof fn', function() {
+			assert.isFunction(axe.utils.getFlattenedTree);
+		});
+		it('el => arr', function() {
+			assert.isArray(axe.utils.getFlattenedTree(document.body));
+		});
+		it('el => [{root}]', function() {
+			assert.lengthOf(
+				axe.utils.getFlattenedTree(randomNodeInTree(isElement)),
+				1
+			);
+		});
+	});
+
+	describe('axe.utils.getNodeFromTree', function() {
+		it('typeof fn', function() {
+			assert.isFunction(axe.utils.getNodeFromTree);
+		});
+		it('node => vnode', function() {
+			axe._tree = axe.utils.getFlattenedTree(document.body);
+			assert.oneOf(
+				axe.utils.getNodeFromTree(randomNodeInTree()),
+				flat(axe._tree[0])
+			);
+		});
+		it('!node => ()', function() {
+			assert.isUndefined(axe.utils.getNodeFromTree(randomElement()));
+		});
+	});
+
+	describe('axe.commons.dom.isOpaque', function() {
+		it('typeof fn', function() {
+			assert.isFunction(axe.commons.dom.isOpaque);
+		});
+		it('el inTree => bool', function() {
+			assert.isBoolean(axe.commons.dom.isOpaque(randomNodeInTree(isElement)));
+		});
+		it('el => bool', function() {
+			assert.isBoolean(axe.commons.dom.isOpaque(randomElement()));
+		});
+	});
+
+	describe('axe.commons.text.accessibleTextVirtual', function() {
+		it('typeof fn', function() {
+			assert.isFunction(axe.commons.text.accessibleTextVirtual);
+		});
+		it('el vnode => str', function() {
+			axe._tree = axe.utils.getFlattenedTree(document.body);
+			var vnode = axe.utils.getNodeFromTree(randomNodeInTree(isElement));
+			assert.isString(axe.commons.text.accessibleTextVirtual(vnode));
+		});
+	});
+});
+
+var elements = [
+	document.createElement('div'),
+	document.createElement('button'),
+	document.createElement('article')
+];
+
+var inTree = [];
+var walker = collectNodes();
+var next = walker.iterate().next();
+while (!next.done) {
+	inTree.push(next.value);
+	next = walker.iterate().next();
+}
+
+function isElement(el) {
+	return el.nodeType === Node.ELEMENT_NODE;
+}
+
+function random(fromArr) {
+	return function(filter) {
+		filter = filter || isTrue;
+		var arr = fromArr.filter(filter);
+		var seed = Math.random();
+		return arr[Math.floor(seed * arr.length)];
+	};
+}
+
+function randomNodeInTree(filter) {
+	return random(inTree)(filter);
+}
+
+function randomElement(filter) {
+	return random(elements)(filter);
+}
+
+// mimic tree: body and all element and text children
+function collectNodes() {
+	var walker = document.createTreeWalker(
+		document,
+		NodeFilter.SHOW_ALL,
+		function(node) {
+			if (!document.body.contains(node)) {
+				return NodeFilter.FILTER_SKIP;
+			}
+			return NodeFilter.FILTER_ACCEPT;
+		}
+	);
+	var next = function() {
+		var value = walker.nextNode();
+		return {
+			value: value,
+			done: !value
+		};
+	};
+	walker.iterate = function() {
+		return { next: next };
+	};
+	return walker;
+}
+
+function flat(tree) {
+	var result = [];
+	var insert = function(node) {
+		result.push(node);
+		(node.children || []).forEach(insert);
+	};
+	if (tree) {
+		insert(tree);
+	}
+	return result;
+}
+
+function isTrue() {
+	return true;
+}