<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.16.0.css" />
    <link rel="stylesheet" href="style.css" />
    
    <script data-semver="1.11.0" src="http://code.jquery.com/jquery-1.11.0.js"></script>
    <script data-semver="3.2.0"  src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    <script data-semver="master" src="http://rawgit.com/Knockout-Contrib/Knockout-Validation/master/Dist/knockout.validation.js"></script>
    <script data-semver="1.16.0" src="http://code.jquery.com/qunit/qunit-1.16.0.js"></script>
    
    <script>
      // jQuery extension to easily access knockout and knockout-validation specifics
      jQuery.fn.extend({
          $config: function() {
            if (this.size() > 1) {
              var result = [];
              this.each(function() {
                result.push(ko.validation.utils.getConfigOptions(this));
              });
              return result;
            }
            return ko.validation.utils.getConfigOptions(this.get(0));
          },
          $context: function() {
            if (this.size() > 1) {
              var result = [];
              this.each(function() {
                result.push(ko.contextFor(this));
              });
              return result;
            }
            return ko.contextFor(this.get(0));
          },
          $viewModel: function() {
            if (this.size() > 1) {
              var result = [];
              this.each(function() {
                result.push(ko.dataFor(this));
              });
              return result;
            }
            return ko.dataFor(this.get(0));
          }
      });
    </script>

    <script src="tests.js"></script>
    <script src="min_max_rule_attribute_spec.js"></script>
  </head>

  <body>
    <div id="qunit"></div>

    <!-- The element used for testing -->
    <div id="testElement"></div>
  </body>

</html>
'use strict';
/*global ko, jQuery, $*/
/*global QUnit:true, module:true, test:true, asyncTest:true, expect:true*/
/*global start:true, stop:true ok:true, equal:true, notEqual:true, deepEqual:true*/
/*global notDeepEqual:true, strictEqual:true, notStrictEqual:true, raises:true*/


//
// Helper method to set HTML content to test element
//
function addTestHtml(contents) {
  jQuery('#testElement').html(contents);
}

function applyTestBindingsWithValidation(viewModel, options) {
    ko.applyBindingsWithValidation(viewModel, jQuery('#testElement').get(0), options);
}

function applyTestBindings(viewModel) {
    ko.applyBindings(viewModel, jQuery('#testElement').get(0));
}


//
// Rename this method to writeInputValidationAttributes to make tests pass
//
ko.validation._writeInputValidationAttributes = function (element, valueAccessor) {
	var observable = valueAccessor();

	if (!observable || !observable.rules) {
		return;
	}

	var contexts = observable.rules(); // observable array

	// loop through the attributes and add the information needed
	ko.utils.arrayForEach(ko.validation.configuration.html5Attributes, function (attr) {
		var params;
		var ctx = ko.utils.arrayFirst(contexts, function (ctx) {
			return ctx.rule && ctx.rule.toLowerCase() === attr.toLowerCase();
		});

		if (!ctx) {
			return;
		}

		params = ctx.params;

		// we have to do some special things for the pattern validation
		if (ctx.rule === "pattern") {
			if (ctx.params instanceof RegExp) {
				params = ctx.params.source; // we need the pure string representation of the RegExpr without the //gi stuff
			}
		}

    ko.computed({
      read: function() {
        element.setAttribute(attr, ko.unwrap(params));
      },
      disposeWhenNodeIsRemoved: element
    });

	});

	contexts = null;
};
/* Styles go here */
# Knockout-Validation - qUnit Tests

> Template for creating tests using qUnit for Knockout-Validation library.

## Writing Tests

Tests should be written in ```tests.js``` file.
The DOM element used for testing has an ID of ```testElement```. 
'use strict';
/*global ko, jQuery, $*/
/*global QUnit:true, module:true, test:true, asyncTest:true, expect:true*/
/*global start:true, stop:true ok:true, equal:true, notEqual:true, deepEqual:true*/
/*global notDeepEqual:true, strictEqual:true, notStrictEqual:true, raises:true*/


module('validatedObservable', {
    beforeEach: function() {
        ko.validation.init({writeInputAttributes: true}, true);
    },
    afterEach: function() {
        var $element = jQuery('#testElement');
        ko.cleanNode($element.get(0));
        $element.empty();
        ko.validation.reset();
    }    
});


// Showing that min rule supports params as observable
//
test('min rule supports observable params', function() {
  expect(6);

  var minValue = ko.observable(4);
  var testObj = ko.observable(10).extend({min: minValue});
  
  strictEqual(testObj(), 10, 'observable still works');
  strictEqual(testObj.isValid(), true, 'observable is valid');
  strictEqual(testObj.error(), null, 'message is properly formatted');

  minValue(15);

  strictEqual(testObj(), 10, 'observable still works after changing params value');
  strictEqual(testObj.isValid(), false, 'observable is not valid');
  strictEqual(testObj.error(), 'Please enter a value greater than or equal to 15.', 'message is properly formatted');
});


// Showing that max rule supports params as observable
//
test('max rule supports observable params', function() {
  expect(6);

  var maxValue = ko.observable(4);
  var testObj = ko.observable(3).extend({max: maxValue});
  
  strictEqual(testObj(), 3, 'observable still works');
  strictEqual(testObj.isValid(), true, 'observable is valid');
  strictEqual(testObj.error(), null, 'message is properly formatted');

  maxValue(2);

  strictEqual(testObj(), 3, 'observable still works after changing params value');
  strictEqual(testObj.isValid(), false, 'observable is not valid');
  strictEqual(testObj.error(), 'Please enter a value less than or equal to 2.', 'message is properly formatted');
});


// Showing that writeInputAttributes does not unwrap params to set min attribute
//
test('Issue #481 - writeInputAttributes doesn\'t unwrap params to set min attribute', function() {
  expect(8);

  var _minValue = ko.observable(4);
  var minValue = ko.computed({read: _minValue});
  
  var testObj = ko.observable(10).extend({min: minValue});
  var $element = jQuery('<input type="text" data-bind="value: value">');
  
  addTestHtml($element);
  applyTestBindings({value: testObj});

  strictEqual(testObj(), 10, 'observable still works');
  strictEqual(testObj.isValid(), true, 'observable is valid');
  strictEqual(testObj.error(), null, 'message is properly formatted');
  strictEqual($element.attr('min'), '4', 'min attribute is written');

  _minValue(15);

  strictEqual(testObj(), 10, 'observable still works after changing params value');
  strictEqual(testObj.isValid(), false, 'observable is not valid');
  strictEqual(testObj.error(), 'Please enter a value greater than or equal to 15.', 'message is properly formatted');
  strictEqual($element.attr('min'), '15', 'min attribute is written');
});


// Showing that writeInputAttributes does not unwrap params to set max attribute
//
test('Issue #481 - writeInputAttributes doesn\'t unwrap params to set min attribute', function() {
  expect(8);

  var _maxValue = ko.observable(4);
  var maxValue = ko.computed({read: _maxValue});
  
  var testObj = ko.observable(3).extend({max: maxValue});
  var $element = jQuery('<input type="text" data-bind="value: value">');
  
  addTestHtml($element);
  applyTestBindings({value: testObj});
  
  strictEqual(testObj(), 3, 'observable still works');
  strictEqual(testObj.isValid(), true, 'observable is valid');
  strictEqual(testObj.error(), null, 'message is properly formatted');
  strictEqual($element.attr('max'), '4', 'max attribute is written');

  _maxValue(2);

  strictEqual(testObj(), 3, 'observable still works after changing params value');
  strictEqual(testObj.isValid(), false, 'observable is not valid');
  strictEqual(testObj.error(), 'Please enter a value less than or equal to 2.', 'message is properly formatted');
  strictEqual($element.attr('max'), '2', 'max attribute is written');
});