module("AuditConfiguration", {
  setup: function() {
    this.auditRules_ = axs.AuditRules.getRules().filter(function(auditRule) {
        return !auditRule.requiresConsoleAPI;
    }).map(function(auditRule) {
        return auditRule.name;
    });
  }
});

test("Basic AuditConfiguration with no customisation", function() {
  // Setup fixture
  var fixtures = document.getElementById('qunit-fixture');
  var auditConfig = new axs.AuditConfiguration();
  auditConfig.scope = fixtures;  // limit scope to just fixture element
  auditConfig.walkDom = false;  // for performance reasons ensure that the entire DOM is not traversed
  var results = axs.Audit.run(auditConfig);
  equal(this.auditRules_.length, results.length);
  var sortedAuditRules = this.auditRules_.sort();
  var sortedResults = results.sort(function(r1, r2) {
    var r1Name = r1.rule.name;
    var r2Name = r2.rule.name;
    return r1Name.localeCompare(r2Name);
  });
  for (var i = 0; i < sortedAuditRules.length; i++)
      equal(sortedAuditRules[i], sortedResults[i].rule.name);
});

test("Configure severity of an audit rule", function() {
  // Setup fixture
  var fixtures = document.getElementById('qunit-fixture');
  var div = document.createElement('div');
  div.setAttribute('role', 'not-an-aria-role');
  fixtures.appendChild(div);

  var auditConfig = new axs.AuditConfiguration();
  auditConfig.scope = fixtures;  // limit scope to just fixture element
  auditConfig.walkDom = false;  // for performance reasons ensure that the entire DOM is not traversed
  auditConfig.setSeverity('badAriaRole', axs.constants.Severity.WARNING);
  var results = axs.Audit.run(auditConfig);
  for (var i = 0; i < results.length; i++) {
    if (results[i].rule.name != 'badAriaRole')
      continue;
    var result = results[i];
    equal(result.rule.severity, axs.constants.Severity.WARNING);
    notEqual(result.rule.severity, axs.AuditRules.getRule('badAriaRole').severity);
    return;
  }
});

test("Specify configuration as an object", function() {
  var fixtures = document.getElementById('qunit-fixture');

  var configPayload = {
    auditRulesToRun: ['badAriaRole'],
    scope: fixtures,
    maxResults: 1
  };

  var auditConfig = new axs.AuditConfiguration(configPayload);

  for (var k in configPayload) {
    equal(auditConfig[k], configPayload[k]);
  }
});

test("Configure the number of results returned", function() {
  var fixture = document.getElementById('qunit-fixture');
  var div = document.createElement('div');
  div.setAttribute('role', 'not-an-aria-role');
  fixture.appendChild(div);
  var div2 = document.createElement('div');
  div2.setAttribute('role', 'also-not-an-aria-role');
  fixture.appendChild(div2);
  var auditConfig = new axs.AuditConfiguration();
  auditConfig.auditRulesToRun = ['badAriaRole'];
  auditConfig.scope = fixture;  // limit scope to just fixture element
  auditConfig.walkDom = false;

  var results = axs.Audit.run(auditConfig);
  equal(results.length, 1);
  equal(results[0].elements.length, 2)

  auditConfig.maxResults = 1;
  results = axs.Audit.run(auditConfig);
  equal(results.length, 1);
  equal(results[0].elements.length, 1)
});

test('Configure audit rules to ignore', function() {
  var fixture = document.getElementById('qunit-fixture');
  var div = document.createElement('div');
  div.setAttribute('role', 'not-an-aria-role');
  fixture.appendChild(div);

  var auditConfig = new axs.AuditConfiguration();
  auditConfig.scope = fixture;  // limit scope to just fixture element
  auditConfig.walkDom = false;

  var results = axs.Audit.run(auditConfig);
  equal(true, results.some(function(result) {
    return result.rule.name == 'badAriaRole' &&
           result.result == 'FAIL';
  }));

  auditConfig.auditRulesToIgnore = ['badAriaRole']
  var results = axs.Audit.run(auditConfig);
  equal(false, results.some(function(result) {
    return result.rule.name == 'badAriaRole';
  }));

});

var __warnings = [];
console.warn = function(msg) {
  __warnings.push(msg);
}

test("Unsupported Rules Warning shown first and only first time audit ran", function() {
  var auditConfig = new axs.AuditConfiguration();
  auditConfig.walkDom = false;  // for performance reasons ensure that the entire DOM is not traversed
  // This should not be touched by an end-user, but needs to be set here,
  // because the unit tests run multiple times Audit.run()
  axs.Audit.unsupportedRulesWarningShown = false;
  __warnings = [];
  axs.Audit.run(auditConfig);

  equal(2, __warnings.length);
  axs.Audit.run(auditConfig);
  equal(2, __warnings.length);
});


test("Unsupported Rules Warning not shown if showUnsupportedRulesWarning set to false on configuration", function() {
  var auditConfig = new axs.AuditConfiguration();
  auditConfig.showUnsupportedRulesWarning = false;
  // This should not be touched by an end-user, but needs to be set here,
  // because the unit tests run multiple times Audit.run()
  axs.Audit.unsupportedRulesWarningShown = false;
  auditConfig.walkDom = false;  // for performance reasons ensure that the entire DOM is not traversed
  __warnings = [];
  axs.Audit.run(auditConfig);

  equal(0, __warnings.length);
  axs.Audit.run(auditConfig);
  equal(0, __warnings.length);
});


test("Unsupported Rules Warning not shown if with console API on configuration set", function() {
  var auditConfig = new axs.AuditConfiguration();
  auditConfig.walkDom = false;  // for performance reasons ensure that the entire DOM is not traversed
  auditConfig.withConsoleApi = true;
  // This should not be touched by an end-user, but needs to be set here,
  // because the unit tests run multiple times Audit.run()
  axs.Audit.unsupportedRulesWarningShown = false;
  __warnings = [];

  getEventListeners = function() { return {"click" : function() { }}; }  // Stub function only in consoleAPI

  axs.Audit.run(auditConfig);

  // Line below would be nice to cleanup, but then the test fails.
  // getEventListeners = null;


  equal(0, __warnings.length);
  axs.Audit.run(auditConfig);
  equal(0, __warnings.length);
});

test("Configure LinkWithUnclearPurpose: blacklist phrase", function() {
  var fixture = document.getElementById('qunit-fixture');
  var a = document.createElement('a');
  a.href = '#main';
  a.textContent = 'Generic text.';
  fixture.appendChild(a);

  var auditConfig = new axs.AuditConfiguration();
  auditConfig.scope = fixture;
  auditConfig.walkDom = false;

  var results = axs.Audit.run(auditConfig);
  equal(results.some(function(result) {
    return result.rule.name == 'linkWithUnclearPurpose' &&
           result.result == 'PASS';
  }), true, 'Before configuration, "Generic text." is acceptable.');

  a.textContent = "Click here."
  var results = axs.Audit.run(auditConfig);
  equal(results.some(function(result) {
    return result.rule.name == 'linkWithUnclearPurpose' &&
           result.result == 'FAIL';
  }), true, '"Click here." should be blocked before configuration');

  auditConfig.setRuleConfig('linkWithUnclearPurpose',
                            { blacklistPhrases: ['generic text'] });

  // Blacklist phrase is matched case-insensitively and ignoring punctuation at
  // the end.
  a.textContent = "Generic text."
  var results = axs.Audit.run(auditConfig);
  equal(results.some(function(result) {
    return result.rule.name == 'linkWithUnclearPurpose' &&
           result.result == 'FAIL';
  }), true, '"Generic text." matches blacklist phrase and should fail');

  // Blacklist phrase must match entire string.
  a.textContent = "Phrase containing generic text";
  var results = axs.Audit.run(auditConfig);
  equal(results.some(function(result) {
    return result.rule.name == 'linkWithUnclearPurpose' &&
           result.result == 'PASS';
  }), true, '"Phrase containing generic text" should pass');

  // Demonstrating the difference between a blacklist phrase and stopwords: a
  // blacklist phrase will only cause an audit failure if the entire string
  // matches the phrase.
  a.textContent = "Generic generic text";
  var results = axs.Audit.run(auditConfig);
  equal(results.some(function(result) {
    return result.rule.name == 'linkWithUnclearPurpose' &&
           result.result == 'PASS';
  }), true,
  '"Generic generic text" does not match blacklist phrase and should pass');

  // After configuration, "Click here." is still blocked by stop words since we
  // didn't configure them.
  a.textContent = "Click here."
  var results = axs.Audit.run(auditConfig);
  equal(results.some(function(result) {
    return result.rule.name == 'linkWithUnclearPurpose' &&
           result.result == 'FAIL';
  }), true, '"Click here" should still be blocked.');
});

test("Configure LinkWithUnclearPurpose: stopwords", function() {
  var fixture = document.getElementById('qunit-fixture');
  var a = document.createElement('a');
  a.href = '#main';
  a.textContent = 'Generic text.';
  fixture.appendChild(a);

  var auditConfig = new axs.AuditConfiguration();
  auditConfig.scope = fixture;
  auditConfig.walkDom = false;

  var results = axs.Audit.run(auditConfig);
  equal(results.some(function(result) {
    return result.rule.name == 'linkWithUnclearPurpose' &&
           result.result == 'PASS';
  }), true, 'Before configuration, "Generic text." is acceptable.');

  a.textContent = "Click here."
  var results = axs.Audit.run(auditConfig);
  equal(results.some(function(result) {
    return result.rule.name == 'linkWithUnclearPurpose' &&
           result.result == 'FAIL';
  }), true, 'Before configuration, "Click here." is blocked by stop words.');

  auditConfig.setRuleConfig('linkWithUnclearPurpose',
                            { stopwords: [ 'generic', 'text' ] });

  // Since this phrase now consists entirely of stop words and punctuation, the
  // test will fail.
  a.textContent = 'Generic text.';
  var results = axs.Audit.run(auditConfig);
  equal(results.some(function(result) {
    return result.rule.name == 'linkWithUnclearPurpose' &&
           result.result == 'FAIL';
  }), true, '"Generic text." should be blocked by stopwords.');

  // Stop words will be filtered out, but if any text remains the test will
  // still pass.
  a.textContent = "Phrase containing generic text";
  var results = axs.Audit.run(auditConfig);
  equal(results.some(function(result) {
    return result.rule.name == 'linkWithUnclearPurpose' &&
           result.result == 'PASS';
  }), true, '"Phrase containing generic text" should not be blocked.');

  // Demonstrating the difference between a blacklist phrase and stopwords:
  // stopwords will be filtered out of the phrase, and if no text remains the
  // test will fail.
  a.textContent = "Generic generic text";
  var results = axs.Audit.run(auditConfig);
  equal(results.some(function(result) {
    return result.rule.name == 'linkWithUnclearPurpose' &&
           result.result == 'FAIL';
  }), true, '"Generic generic text" should be blocked.');

  // After configuration, "Click here." is no longer blocked by stop words.
  a.textContent = "Click here."
  var results = axs.Audit.run(auditConfig);
  equal(results.some(function(result) {
    return result.rule.name == 'linkWithUnclearPurpose' &&
           result.result == 'PASS';
  }), true, '"Click here" should no longer be blocked.');
});
