From 9c5063a6a8b2bb21c5f551575446e84b78c317b4 Mon Sep 17 00:00:00 2001 From: Brian Cardarella Date: Thu, 24 Nov 2016 11:48:33 -0500 Subject: [PATCH 1/3] First pass at new easy-form * form-for * input control * textarea control Controls have label and helpers --- .editorconfig | 14 --- .eslintrc.js | 13 ++ .gitignore | 2 +- .jshintrc | 32 ----- .travis.yml | 7 +- README.md | 9 +- addon/components/form-control-helper.js | 7 ++ addon/components/form-controls/-base.js | 35 ++++++ addon/components/form-controls/input.js | 44 +++++++ addon/components/form-controls/textarea.js | 5 + addon/components/form-for.js | 38 ++++++ .../components/form-control-helper.hbs | 5 + .../components/form-controls/-base.hbs | 9 ++ addon/templates/components/form-for.hbs | 4 + app/components/form-control-helper.js | 1 + app/components/form-controls/input.js | 1 + app/components/form-controls/textarea.js | 1 + app/components/form-for.js | 1 + bower.json | 6 +- config/ember-try.js | 15 ++- package.json | 33 +++--- tests/.eslintrc.js | 5 + tests/.jshintrc | 52 -------- tests/dummy/app/index.html | 8 +- tests/dummy/app/router.js | 3 +- tests/dummy/app/routes/application.js | 11 ++ tests/dummy/app/templates/application.hbs | 4 + tests/dummy/config/environment.js | 7 +- tests/helpers/actions.js | 34 ++++++ tests/helpers/events.js | 112 ++++++++++++++++++ tests/index.html | 17 ++- .../components/form-control-helper-test.js | 21 ++++ .../components/form-controls/input-test.js | 40 +++++++ .../components/form-controls/textarea-test.js | 35 ++++++ tests/integration/components/form-for-test.js | 72 +++++++++++ .../components/form-controls/input-test.js | 74 ++++++++++++ 36 files changed, 631 insertions(+), 146 deletions(-) create mode 100644 .eslintrc.js delete mode 100644 .jshintrc create mode 100644 addon/components/form-control-helper.js create mode 100644 addon/components/form-controls/-base.js create mode 100644 addon/components/form-controls/input.js create mode 100644 addon/components/form-controls/textarea.js create mode 100644 addon/components/form-for.js create mode 100644 addon/templates/components/form-control-helper.hbs create mode 100644 addon/templates/components/form-controls/-base.hbs create mode 100644 addon/templates/components/form-for.hbs create mode 100644 app/components/form-control-helper.js create mode 100644 app/components/form-controls/input.js create mode 100644 app/components/form-controls/textarea.js create mode 100644 app/components/form-for.js create mode 100644 tests/.eslintrc.js delete mode 100644 tests/.jshintrc create mode 100644 tests/dummy/app/routes/application.js create mode 100644 tests/dummy/app/templates/application.hbs create mode 100644 tests/helpers/actions.js create mode 100644 tests/helpers/events.js create mode 100644 tests/integration/components/form-control-helper-test.js create mode 100644 tests/integration/components/form-controls/input-test.js create mode 100644 tests/integration/components/form-controls/textarea-test.js create mode 100644 tests/integration/components/form-for-test.js create mode 100644 tests/unit/components/form-controls/input-test.js diff --git a/.editorconfig b/.editorconfig index 47c5438..219985c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,22 +13,8 @@ insert_final_newline = true indent_style = space indent_size = 2 -[*.js] -indent_style = space -indent_size = 2 - [*.hbs] insert_final_newline = false -indent_style = space -indent_size = 2 - -[*.css] -indent_style = space -indent_size = 2 - -[*.html] -indent_style = space -indent_size = 2 [*.{diff,md}] trim_trailing_whitespace = false diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..2978e35 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,13 @@ +module.exports = { + root: true, + parserOptions: { + ecmaVersion: 6, + sourceType: 'module' + }, + extends: 'eslint:recommended', + env: { + 'browser': true + }, + rules: { + } +}; diff --git a/.gitignore b/.gitignore index 86fceae..373de6a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,5 @@ /connect.lock /coverage/* /libpeerconnection.log -npm-debug.log +npm-debug.log* testem.log diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 08096ef..0000000 --- a/.jshintrc +++ /dev/null @@ -1,32 +0,0 @@ -{ - "predef": [ - "document", - "window", - "-Promise" - ], - "browser": true, - "boss": true, - "curly": true, - "debug": false, - "devel": true, - "eqeqeq": true, - "evil": true, - "forin": false, - "immed": false, - "laxbreak": false, - "newcap": true, - "noarg": true, - "noempty": false, - "nonew": false, - "nomen": false, - "onevar": false, - "plusplus": false, - "regexp": false, - "undef": true, - "sub": true, - "strict": false, - "white": false, - "eqnull": true, - "esnext": true, - "unused": true -} diff --git a/.travis.yml b/.travis.yml index 00c5822..b3dfc66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,9 @@ cache: - node_modules env: - - EMBER_TRY_SCENARIO=default + # we recommend testing LTS's and latest stable release (bonus points to beta/canary) - EMBER_TRY_SCENARIO=ember-1.13 + - EMBER_TRY_SCENARIO=ember-lts-2.4 - EMBER_TRY_SCENARIO=ember-release - EMBER_TRY_SCENARIO=ember-beta - EMBER_TRY_SCENARIO=ember-canary @@ -24,7 +25,9 @@ matrix: before_install: - npm config set spin false - npm install -g bower + - bower --version - npm install phantomjs-prebuilt + - node_modules/phantomjs-prebuilt/bin/phantomjs --version install: - npm install @@ -33,4 +36,4 @@ install: script: # Usually, it's ok to finish the test scenario without reverting # to the addon's original dependency state, skipping "cleanup". - - ember try $EMBER_TRY_SCENARIO test --skip-cleanup + - ember try:one $EMBER_TRY_SCENARIO test --skip-cleanup diff --git a/README.md b/README.md index 2ddca2a..1c92c78 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,19 @@ This README outlines the details of collaborating on this Ember addon. ## Installation -* `git clone` this repository +* `git clone ` this repository +* `cd ember-easy-form` * `npm install` * `bower install` ## Running -* `ember server` -* Visit your app at http://localhost:4200. +* `ember serve` +* Visit your app at [http://localhost:4200](http://localhost:4200). ## Running Tests -* `npm test` (Runs `ember try:testall` to test your addon against multiple Ember versions) +* `npm test` (Runs `ember try:each` to test your addon against multiple Ember versions) * `ember test` * `ember test --server` diff --git a/addon/components/form-control-helper.js b/addon/components/form-control-helper.js new file mode 100644 index 0000000..e4fdfa6 --- /dev/null +++ b/addon/components/form-control-helper.js @@ -0,0 +1,7 @@ +import Ember from 'ember'; +import layout from '../templates/components/form-control-helper'; + +export default Ember.Component.extend({ + layout, + classNames: ['form-control-helper'] +}); diff --git a/addon/components/form-controls/-base.js b/addon/components/form-controls/-base.js new file mode 100644 index 0000000..59dd56f --- /dev/null +++ b/addon/components/form-controls/-base.js @@ -0,0 +1,35 @@ +import Ember from 'ember'; +import layout from '../../templates/components/form-controls/-base'; + +const { + get, + set, + guidFor, + computed, + computed: { alias }, + String: { capitalize }, + Component +} = Ember; + +let BaseComponent = Component.extend({ + layout, + init() { + let property = get(this, 'property'); + let value = alias(`subject.${property}`); + set(this, 'value', value); + return this._super(...arguments); + }, + controlId: computed(function() { + return guidFor({}); + }), + label: computed(function() { + let property = get(this, 'property'); + return capitalize(property); + }) +}); + +BaseComponent.reopenClass({ + positionalParams: ['property'] +}); + +export default BaseComponent; diff --git a/addon/components/form-controls/input.js b/addon/components/form-controls/input.js new file mode 100644 index 0000000..7a28cf7 --- /dev/null +++ b/addon/components/form-controls/input.js @@ -0,0 +1,44 @@ +import Ember from 'ember' +import BaseComponent from './-base'; + +const { + get, + computed +} = Ember; + +const types = [ + 'color', + 'datetime-local', + 'datetime', + 'date', + 'time', + 'email', + 'file', + 'month', + 'number', + 'password', + 'range', + 'search', + 'tel', + 'text', + 'url', + 'week' +]; + +export default BaseComponent.extend({ + controlType: '-text-field', + + type: computed('property', function() { + let property = get(this, 'property').toLowerCase(); + let type; + + for (let i = 0; i < types.length; i++) { + if (property.indexOf(types[i]) > -1) { + type = types[i]; + break; + } + } + + return type || 'text'; + }) +}); diff --git a/addon/components/form-controls/textarea.js b/addon/components/form-controls/textarea.js new file mode 100644 index 0000000..437eed2 --- /dev/null +++ b/addon/components/form-controls/textarea.js @@ -0,0 +1,5 @@ +import BaseComponent from './-base'; + +export default BaseComponent.extend({ + controlType: '-text-area' +}); diff --git a/addon/components/form-for.js b/addon/components/form-for.js new file mode 100644 index 0000000..3e08465 --- /dev/null +++ b/addon/components/form-for.js @@ -0,0 +1,38 @@ +import Ember from 'ember'; +import layout from '../templates/components/form-for'; + +const { + get, + Component, + Error: EmberError +} = Ember; + +let FormForComponent = Component.extend({ + layout, + classNames: ['easy-form'], + tagName: 'form', + + init() { + let subject = get(this, 'subject'); + + if (!subject) { + let error = new EmberError('subject must be passed to `form-for` as either positional param or explicit param'); + throw(error); + } + + for (let key in this) { + if (key.indexOf('HAS_BLOCK') !== -1 && !this[key]) { + let error = new EmberError('cannot take inline, only block'); + throw(error); + } + } + + return this._super(...arguments); + } +}); + +FormForComponent.reopenClass({ + positionalParams: ['subject'] +}); + +export default FormForComponent; diff --git a/addon/templates/components/form-control-helper.hbs b/addon/templates/components/form-control-helper.hbs new file mode 100644 index 0000000..e347e48 --- /dev/null +++ b/addon/templates/components/form-control-helper.hbs @@ -0,0 +1,5 @@ +{{#if hasBlock}} + {{yield}} +{{else}} + {{text}} +{{/if}} diff --git a/addon/templates/components/form-controls/-base.hbs b/addon/templates/components/form-controls/-base.hbs new file mode 100644 index 0000000..15eda3f --- /dev/null +++ b/addon/templates/components/form-controls/-base.hbs @@ -0,0 +1,9 @@ +{{#if hasBlock}} + {{yield}} +{{else}} + + {{component controlType id=controlId value=value type=type}} + {{#if helper}} + {{form-control-helper text=helper}} + {{/if}} +{{/if}} diff --git a/addon/templates/components/form-for.hbs b/addon/templates/components/form-for.hbs new file mode 100644 index 0000000..a1c099e --- /dev/null +++ b/addon/templates/components/form-for.hbs @@ -0,0 +1,4 @@ +{{yield (hash + input=(component "form-controls/input" subject=subject) + textarea=(component "form-controls/textarea" subject=subject) +)}} diff --git a/app/components/form-control-helper.js b/app/components/form-control-helper.js new file mode 100644 index 0000000..176d035 --- /dev/null +++ b/app/components/form-control-helper.js @@ -0,0 +1 @@ +export { default } from 'ember-easy-form/components/form-control-helper'; \ No newline at end of file diff --git a/app/components/form-controls/input.js b/app/components/form-controls/input.js new file mode 100644 index 0000000..7dd3a8d --- /dev/null +++ b/app/components/form-controls/input.js @@ -0,0 +1 @@ +export { default } from 'ember-easy-form/components/form-controls/input'; diff --git a/app/components/form-controls/textarea.js b/app/components/form-controls/textarea.js new file mode 100644 index 0000000..d8c0df0 --- /dev/null +++ b/app/components/form-controls/textarea.js @@ -0,0 +1 @@ +export { default } from 'ember-easy-form/components/form-controls/textarea'; diff --git a/app/components/form-for.js b/app/components/form-for.js new file mode 100644 index 0000000..13f1810 --- /dev/null +++ b/app/components/form-for.js @@ -0,0 +1 @@ +export { default } from 'ember-easy-form/components/form-for'; \ No newline at end of file diff --git a/bower.json b/bower.json index b95c206..26bf7f1 100644 --- a/bower.json +++ b/bower.json @@ -1,9 +1,7 @@ { "name": "ember-easy-form", "dependencies": { - "ember": "~2.5.0", - "ember-cli-shims": "0.1.1", - "ember-cli-test-loader": "0.2.2", - "ember-qunit-notifications": "0.1.0" + "ember": "~2.10.0-beta.3", + "ember-cli-shims": "0.1.3" } } diff --git a/config/ember-try.js b/config/ember-try.js index 014f603..0355b5f 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -2,19 +2,24 @@ module.exports = { scenarios: [ { - name: 'default', + name: 'ember-1.13', bower: { - dependencies: { } + dependencies: { + 'ember': '~1.13.0' + }, + resolutions: { + 'ember': '~1.13.0' + } } }, { - name: 'ember-1.13', + name: 'ember-lts-2.4', bower: { dependencies: { - 'ember': '~1.13.0' + 'ember': 'components/ember#lts-2-4' }, resolutions: { - 'ember': '~1.13.0' + 'ember': 'lts-2-4' } } }, diff --git a/package.json b/package.json index 79b567e..1569899 100644 --- a/package.json +++ b/package.json @@ -13,37 +13,38 @@ }, "repository": "", "engines": { - "node": ">= 0.10.0" + "node": ">= 0.12.0" }, "author": "", "license": "MIT", "devDependencies": { - "broccoli-asset-rev": "^2.4.2", - "ember-ajax": "^2.0.1", - "ember-cli": "2.6.0-beta.1", - "ember-cli-app-version": "^1.0.0", - "ember-cli-dependency-checker": "^1.2.0", - "ember-cli-htmlbars": "^1.0.3", - "ember-cli-htmlbars-inline-precompile": "^0.3.1", - "ember-cli-inject-live-reload": "^1.4.0", - "ember-cli-jshint": "^1.0.0", - "ember-cli-qunit": "^1.4.0", - "ember-cli-release": "0.2.8", + "broccoli-asset-rev": "^2.4.5", + "ember-ajax": "^2.4.1", + "ember-cli": "2.9.1", + "ember-cli-app-version": "^2.0.0", + "ember-cli-dependency-checker": "^1.3.0", + "ember-cli-eslint": "3.0.0", + "ember-cli-htmlbars-inline-precompile": "^0.3.3", + "ember-cli-inject-live-reload": "^1.4.1", + "ember-cli-qunit": "^3.0.1", + "ember-cli-release": "^0.2.9", "ember-cli-sri": "^2.1.0", + "ember-cli-test-loader": "^1.1.0", "ember-cli-uglify": "^1.2.0", - "ember-data": "^2.5.0", + "ember-data": "^2.9.0", "ember-disable-prototype-extensions": "^1.1.0", "ember-export-application-global": "^1.0.5", "ember-load-initializers": "^0.5.1", "ember-resolver": "^2.0.3", - "ember-welcome-page": "^1.0.1", - "loader.js": "^4.0.1" + "eslint-plugin-ember-suave": "^1.0.0", + "loader.js": "^4.0.10" }, "keywords": [ "ember-addon" ], "dependencies": { - "ember-cli-babel": "^5.1.6" + "ember-cli-babel": "^5.1.7", + "ember-cli-htmlbars": "^1.0.10" }, "ember-addon": { "configPath": "tests/dummy/config" diff --git a/tests/.eslintrc.js b/tests/.eslintrc.js new file mode 100644 index 0000000..9fc5132 --- /dev/null +++ b/tests/.eslintrc.js @@ -0,0 +1,5 @@ +module.exports = { + env: { + 'embertest': true + } +}; diff --git a/tests/.jshintrc b/tests/.jshintrc deleted file mode 100644 index 6ec0b7c..0000000 --- a/tests/.jshintrc +++ /dev/null @@ -1,52 +0,0 @@ -{ - "predef": [ - "document", - "window", - "location", - "setTimeout", - "$", - "-Promise", - "define", - "console", - "visit", - "exists", - "fillIn", - "click", - "keyEvent", - "triggerEvent", - "find", - "findWithAssert", - "wait", - "DS", - "andThen", - "currentURL", - "currentPath", - "currentRouteName" - ], - "node": false, - "browser": false, - "boss": true, - "curly": true, - "debug": false, - "devel": false, - "eqeqeq": true, - "evil": true, - "forin": false, - "immed": false, - "laxbreak": false, - "newcap": true, - "noarg": true, - "noempty": false, - "nonew": false, - "nomen": false, - "onevar": false, - "plusplus": false, - "regexp": false, - "undef": true, - "sub": true, - "strict": false, - "white": false, - "eqnull": true, - "esnext": true, - "unused": true -} diff --git a/tests/dummy/app/index.html b/tests/dummy/app/index.html index c9b4327..5120bd7 100644 --- a/tests/dummy/app/index.html +++ b/tests/dummy/app/index.html @@ -9,16 +9,16 @@ {{content-for "head"}} - - + + {{content-for "head-footer"}} {{content-for "body"}} - - + + {{content-for "body-footer"}} diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index 3bba78e..cdc2578 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -2,7 +2,8 @@ import Ember from 'ember'; import config from './config/environment'; const Router = Ember.Router.extend({ - location: config.locationType + location: config.locationType, + rootURL: config.rootURL }); Router.map(function() { diff --git a/tests/dummy/app/routes/application.js b/tests/dummy/app/routes/application.js new file mode 100644 index 0000000..cda92cf --- /dev/null +++ b/tests/dummy/app/routes/application.js @@ -0,0 +1,11 @@ +import Ember from 'ember'; + +const { + Route +} = Ember; + +export default Route.extend({ + model() { + return { name: 'Foobar' }; + } +}); diff --git a/tests/dummy/app/templates/application.hbs b/tests/dummy/app/templates/application.hbs new file mode 100644 index 0000000..a4e640b --- /dev/null +++ b/tests/dummy/app/templates/application.hbs @@ -0,0 +1,4 @@ +{{#form-for model as |f|}} + {{f.input "name" label="fobar"}} + {{f.textarea "bio"}} +{{/form-for}} diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index c59bcd5..703c472 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -4,12 +4,16 @@ module.exports = function(environment) { var ENV = { modulePrefix: 'dummy', environment: environment, - baseURL: '/', + rootURL: '/', locationType: 'auto', EmberENV: { FEATURES: { // Here you can enable experimental features on an ember canary build // e.g. 'with-controller': true + }, + EXTEND_PROTOTYPES: { + // Prevent Ember Data from overriding Date.parse. + Date: false } }, @@ -29,7 +33,6 @@ module.exports = function(environment) { if (environment === 'test') { // Testem prefers this... - ENV.baseURL = '/'; ENV.locationType = 'none'; // keep test console output quieter diff --git a/tests/helpers/actions.js b/tests/helpers/actions.js new file mode 100644 index 0000000..b5ac7ae --- /dev/null +++ b/tests/helpers/actions.js @@ -0,0 +1,34 @@ +import Ember from 'ember'; +import { focus, fireEvent } from './events'; + +const { + run +} = Ember; + +export function fillIn(context, selector, text) { + let $el, el; + $el = findWithAssert(selector, context); + el = $el[0]; + + return run(() => { + focus(el); + + $el.eq(0).val(text); + fireEvent(el, 'input'); + fireEvent(el, 'change'); + }); +} + +export function findWithAssert(selector, context) { + let $el = find(selector, context); + + if ($el.length === 0) { + throw new Error('Element ' + selector + ' not found.'); + } + + return $el; +} + +export function find(selector, context) { + return context.$(selector); +} diff --git a/tests/helpers/events.js b/tests/helpers/events.js new file mode 100644 index 0000000..267e49f --- /dev/null +++ b/tests/helpers/events.js @@ -0,0 +1,112 @@ +import Ember from 'ember'; + +const { + run, + $: jQuery +} = Ember; + +const DEFAULT_EVENT_OPTIONS = { canBubble: true, cancelable: true }; +const KEYBOARD_EVENT_TYPES = ['keydown', 'keypress', 'keyup']; +const MOUSE_EVENT_TYPES = ['click', 'mousedown', 'mouseup', 'dblclick', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover']; + +export function focus(el) { + if (!el) { return; } + let $el = jQuery(el); + if ($el.is(':input, [contenteditable=true]')) { + let type = $el.prop('type'); + if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') { + run(null, function() { + // Firefox does not trigger the `focusin` event if the window + // does not have focus. If the document doesn't have focus just + // use trigger('focusin') instead. + + if (!document.hasFocus || document.hasFocus()) { + el.focus(); + } else { + $el.trigger('focusin'); + } + }); + } + } +} + +export function fireEvent(element, type, options = {}) { + if (!element) { + return; + } + let event; + if (KEYBOARD_EVENT_TYPES.indexOf(type) > -1) { + event = buildKeyboardEvent(type, options); + } else if (MOUSE_EVENT_TYPES.indexOf(type) > -1) { + let rect = element.getBoundingClientRect(); + let x = rect.left + 1; + let y = rect.top + 1; + let simulatedCoordinates = { + screenX: x + 5, + screenY: y + 95, + clientX: x, + clientY: y + }; + event = buildMouseEvent(type, jQuery.extend(simulatedCoordinates, options)); + } else { + event = buildBasicEvent(type, options); + } + element.dispatchEvent(event); +} + +function buildBasicEvent(type, options = {}) { + let event = document.createEvent('Events'); + event.initEvent(type, true, true); + jQuery.extend(event, options); + return event; +} + +function buildMouseEvent(type, options = {}) { + let event; + try { + event = document.createEvent('MouseEvents'); + let eventOpts = jQuery.extend({}, DEFAULT_EVENT_OPTIONS, options); + event.initMouseEvent( + type, + eventOpts.canBubble, + eventOpts.cancelable, + window, + eventOpts.detail, + eventOpts.screenX, + eventOpts.screenY, + eventOpts.clientX, + eventOpts.clientY, + eventOpts.ctrlKey, + eventOpts.altKey, + eventOpts.shiftKey, + eventOpts.metaKey, + eventOpts.button, + eventOpts.relatedTarget); + } catch (e) { + event = buildBasicEvent(type, options); + } + return event; +} + +function buildKeyboardEvent(type, options = {}) { + let event; + try { + event = document.createEvent('KeyEvents'); + let eventOpts = jQuery.extend({}, DEFAULT_EVENT_OPTIONS, options); + event.initKeyEvent( + type, + eventOpts.canBubble, + eventOpts.cancelable, + window, + eventOpts.ctrlKey, + eventOpts.altKey, + eventOpts.shiftKey, + eventOpts.metaKey, + eventOpts.keyCode, + eventOpts.charCode + ); + } catch (e) { + event = buildBasicEvent(type, options); + } + return event; +} diff --git a/tests/index.html b/tests/index.html index 64cb47e..5209b85 100644 --- a/tests/index.html +++ b/tests/index.html @@ -10,9 +10,9 @@ {{content-for "head"}} {{content-for "test-head"}} - - - + + + {{content-for "head-footer"}} {{content-for "test-head-footer"}} @@ -21,12 +21,11 @@ {{content-for "body"}} {{content-for "test-body"}} - - - - - - + + + + + {{content-for "body-footer"}} {{content-for "test-body-footer"}} diff --git a/tests/integration/components/form-control-helper-test.js b/tests/integration/components/form-control-helper-test.js new file mode 100644 index 0000000..f420b59 --- /dev/null +++ b/tests/integration/components/form-control-helper-test.js @@ -0,0 +1,21 @@ +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('form-control-helper', 'Integration | Component | form control helper', { + integration: true +}); + +test('it renders', function(assert) { + this.render(hbs`{{form-control-helper text="foobar"}}`); + + assert.equal(this.$().text().trim(), 'foobar'); + + // Template block usage: + this.render(hbs` + {{#form-control-helper}} + template block text + {{/form-control-helper}} + `); + + assert.equal(this.$().text().trim(), 'template block text'); +}); diff --git a/tests/integration/components/form-controls/input-test.js b/tests/integration/components/form-controls/input-test.js new file mode 100644 index 0000000..ce99626 --- /dev/null +++ b/tests/integration/components/form-controls/input-test.js @@ -0,0 +1,40 @@ +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('form-controls/input', 'Integration | Component | form-controls/input', { + integration: true, + + beforeEach() { + this.set('model', { + name: 'Foo' + }); + } +}); + +test('it by default renders input and associated label', function(assert) { + this.render(hbs`{{form-controls/input "name" subject=model}}`); + + assert.equal(this.$('input').val(), 'Foo'); + assert.equal(this.$('label').text().trim(), 'Name') + assert.equal(this.$('label').prop('for'), this.$('input').prop('id')); + + // does not render helper when no text provided + assert.equal(this.$('div.form-control-helper').length, 0); +}); + +test('it allows for `label` override', function(assert) { + this.render(hbs`{{form-controls/input "name" subject=model label="Your Name"}}`); + + assert.equal(this.$('label').text().trim(), 'Your Name') +}); + +test('it renders helper text', function(assert) { + this.render(hbs`{{form-controls/input "name" subject=model helper="Do this, not that"}}`); + + assert.equal(this.$('div.form-control-helper').text().trim(), 'Do this, not that'); +}); + +test('it can override the input type', function(assert) { + this.render(hbs`{{form-controls/input "name" subject=model type="search"}}`); + assert.equal(this.$('input').prop('type'), 'search'); +}); diff --git a/tests/integration/components/form-controls/textarea-test.js b/tests/integration/components/form-controls/textarea-test.js new file mode 100644 index 0000000..fa4659a --- /dev/null +++ b/tests/integration/components/form-controls/textarea-test.js @@ -0,0 +1,35 @@ +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('form-controls/textarea', 'Integration | Component | form-controls/textarea', { + integration: true, + + beforeEach() { + this.set('model', { + bio: 'Foo' + }); + } +}); + +test('it by default renders textarea and associated label', function(assert) { + this.render(hbs`{{form-controls/textarea "bio" subject=model}}`); + + assert.equal(this.$('textarea').val(), 'Foo'); + assert.equal(this.$('label').text().trim(), 'Bio') + assert.equal(this.$('label').prop('for'), this.$('textarea').prop('id')); + + // does not render helper when no text provided + assert.equal(this.$('div.form-control-helper').length, 0); +}); + +test('it allows for `label` override', function(assert) { + this.render(hbs`{{form-controls/textarea "bio" subject=model label="Your Bio"}}`); + + assert.equal(this.$('label').text().trim(), 'Your Bio') +}); + +test('it renders helper text', function(assert) { + this.render(hbs`{{form-controls/input "name" subject=model helper="Do this, not that"}}`); + + assert.equal(this.$('div.form-control-helper').text().trim(), 'Do this, not that'); +}); diff --git a/tests/integration/components/form-for-test.js b/tests/integration/components/form-for-test.js new file mode 100644 index 0000000..29bc00b --- /dev/null +++ b/tests/integration/components/form-for-test.js @@ -0,0 +1,72 @@ +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; +import { fillIn } from '../../helpers/actions'; + +moduleForComponent('form-for', 'Integration | Component | form for', { + integration: true, + + beforeEach() { + this.set('model', { + name: 'foo' + }); + } +}); + +test('it renders a form', function(assert) { + this.render(hbs` + {{#form-for model}} + {{/form-for}} + `); + + assert.ok(this.$('form.easy-form').length, 1); +}); + +test('it does not accept in-line style', function(assert) { + assert.expect(1); + + assert.throws(() => { + this.render(hbs`{{form-for model}}`); + }, 'cannot take inline, only block'); +}); + +test('it will not accept without the `subject` being set', function(assert) { + assert.expect(2); + + assert.throws(() => { + this.render(hbs` + {{#form-for}} + {{/form-for}} + `); + }, 'subject must be passed to `form-for` as either positional param or explicit param'); + + assert.throws(() => { + this.render(hbs` + {{#form-for foobar}} + {{/form-for}} + `); + }, 'subject must be passed to `form-for` as either positional param or explicit param'); + + try { + this.render(hbs` + {{#form-for model}} + {{/form-for}} + `); + } catch(err) { + assert.notOk(true, 'did not expect an error to be thrown'); + } +}); + +test('can render an input', function(assert) { + this.render(hbs` + {{#form-for model as |f|}} + {{f.input "name"}} + {{f.textarea "bio"}} + {{/form-for}} + `); + + fillIn(this, 'form input', 'Brian'); + fillIn(this, 'form textarea', 'CEO of DockYard'); + + assert.equal(this.get('model.name'), 'Brian'); + assert.equal(this.get('model.bio'), 'CEO of DockYard'); +}); diff --git a/tests/unit/components/form-controls/input-test.js b/tests/unit/components/form-controls/input-test.js new file mode 100644 index 0000000..a1a4494 --- /dev/null +++ b/tests/unit/components/form-controls/input-test.js @@ -0,0 +1,74 @@ +import { moduleFor, test } from 'ember-qunit'; + +moduleFor('component:form-controls/input', 'Unit | Component | form-controls/input'); + +test('will derive allowed type from `property`', function(assert) { + let component = this.subject(); + + component.set('property', 'x-color-y'); + assert.equal(component.get('type'), 'color'); + + component.set('property', 'x-COLOR-y'); + assert.equal(component.get('type'), 'color'); + + component.set('property', 'x-datetime-local-y'); + assert.equal(component.get('type'), 'datetime-local'); + + component.set('property', 'x-date-y'); + assert.equal(component.get('type'), 'date'); + + component.set('property', 'x-time-y'); + assert.equal(component.get('type'), 'time'); + + component.set('property', 'x-email-y'); + assert.equal(component.get('type'), 'email'); + + component.set('property', 'x-file-y'); + assert.equal(component.get('type'), 'file'); + + component.set('property', 'x-month-y'); + assert.equal(component.get('type'), 'month'); + + component.set('property', 'x-number-y'); + assert.equal(component.get('type'), 'number'); + + component.set('property', 'x-password-y'); + assert.equal(component.get('type'), 'password'); + + component.set('property', 'x-range-y'); + assert.equal(component.get('type'), 'range'); + + component.set('property', 'x-search-y'); + assert.equal(component.get('type'), 'search'); + + component.set('property', 'x-tel-y'); + assert.equal(component.get('type'), 'tel'); + + component.set('property', 'x-text-y'); + assert.equal(component.get('type'), 'text'); + + component.set('property', 'x-url-y'); + assert.equal(component.get('type'), 'url'); + + component.set('property', 'x-week-y'); + assert.equal(component.get('type'), 'week'); +}); + +test('does not will derive disallowed type from `property`', function(assert) { + let component = this.subject(); + + component.set('property', 'x-checkbox-y'); + assert.equal(component.get('type'), 'text'); + + component.set('property', 'x-hidden-y'); + assert.equal(component.get('type'), 'text'); + + component.set('property', 'x-image-y'); + assert.equal(component.get('type'), 'text'); + + component.set('property', 'x-reset-y'); + assert.equal(component.get('type'), 'text'); + + component.set('property', 'x-submit-y'); + assert.equal(component.get('type'), 'text'); +}); From 7a36655867203a6c1a2eaccc1b6fa5a401275f44 Mon Sep 17 00:00:00 2001 From: Brian Cardarella Date: Thu, 24 Nov 2016 12:14:05 -0500 Subject: [PATCH 2/3] fix ember try versions --- config/ember-try.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/config/ember-try.js b/config/ember-try.js index 0355b5f..10381b8 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -1,17 +1,6 @@ /*jshint node:true*/ module.exports = { scenarios: [ - { - name: 'ember-1.13', - bower: { - dependencies: { - 'ember': '~1.13.0' - }, - resolutions: { - 'ember': '~1.13.0' - } - } - }, { name: 'ember-lts-2.4', bower: { From 51915983ac669d6233d3518f8ecf2a5296e51d93 Mon Sep 17 00:00:00 2001 From: Brian Cardarella Date: Thu, 24 Nov 2016 12:19:07 -0500 Subject: [PATCH 3/3] Fix travis --- .travis.yml | 3 +-- config/ember-try.js | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index b3dfc66..a592f50 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,7 @@ cache: env: # we recommend testing LTS's and latest stable release (bonus points to beta/canary) - - EMBER_TRY_SCENARIO=ember-1.13 - - EMBER_TRY_SCENARIO=ember-lts-2.4 + - EMBER_TRY_SCENARIO=ember-lts-2.8 - EMBER_TRY_SCENARIO=ember-release - EMBER_TRY_SCENARIO=ember-beta - EMBER_TRY_SCENARIO=ember-canary diff --git a/config/ember-try.js b/config/ember-try.js index 10381b8..c0126c4 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -2,13 +2,13 @@ module.exports = { scenarios: [ { - name: 'ember-lts-2.4', + name: 'ember-lts-2.8', bower: { dependencies: { - 'ember': 'components/ember#lts-2-4' + 'ember': 'components/ember#lts-2-8' }, resolutions: { - 'ember': 'lts-2-4' + 'ember': 'lts-2-8' } } },