├── .doorkeeperrc.js ├── .editorconfig ├── .ember-cli ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .travis.yml ├── .watchmanconfig ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── addon ├── .gitkeep └── validators │ └── sometimes.js ├── app └── .gitkeep ├── config ├── ember-try.js └── environment.js ├── coverage └── coverage-summary.json ├── ember-cli-build.js ├── index.js ├── package-lock.json ├── package.json ├── testem.js ├── tests ├── dummy │ ├── app │ │ ├── app.js │ │ ├── components │ │ │ └── .gitkeep │ │ ├── controllers │ │ │ ├── .gitkeep │ │ │ └── application.js │ │ ├── helpers │ │ │ └── .gitkeep │ │ ├── index.html │ │ ├── models │ │ │ └── .gitkeep │ │ ├── resolver.js │ │ ├── router.js │ │ ├── routes │ │ │ └── .gitkeep │ │ ├── styles │ │ │ └── app.css │ │ ├── templates │ │ │ ├── application.hbs │ │ │ └── components │ │ │ │ └── .gitkeep │ │ └── validations │ │ │ └── settings.js │ ├── config │ │ ├── environment.js │ │ └── targets.js │ └── public │ │ └── robots.txt ├── helpers │ ├── .gitkeep │ ├── destroy-app.js │ ├── is-function.js │ ├── module-for-acceptance.js │ └── start-app.js ├── index.html ├── integration │ └── .gitkeep ├── test-helper.js └── unit │ ├── .gitkeep │ └── validators │ └── sometimes-test.js └── vendor └── .gitkeep /.doorkeeperrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | threshold: 2, 3 | testCommand: 'COVERAGE=true ember try:each', 4 | mainBranch: 'master' 5 | }; 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.hbs] 17 | insert_final_newline = false 18 | 19 | [*.{diff,md}] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false 9 | } 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | /blueprints/*/files/ 3 | /vendor/ 4 | 5 | # compiled output 6 | /dist/ 7 | /tmp/ 8 | 9 | # dependencies 10 | /bower_components/ 11 | 12 | # misc 13 | /coverage/ 14 | 15 | # ember-try 16 | /.node_modules.ember-try/ 17 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | ecmaVersion: 2017, 5 | sourceType: 'module' 6 | }, 7 | plugins: [ 8 | 'ember' 9 | ], 10 | extends: [ 11 | 'eslint:recommended', 12 | 'plugin:ember/recommended' 13 | ], 14 | env: { 15 | browser: true 16 | }, 17 | rules: { 18 | }, 19 | overrides: [ 20 | // node files 21 | { 22 | files: [ 23 | 'ember-cli-build.js', 24 | 'index.js', 25 | 'testem.js', 26 | 'blueprints/*/index.js', 27 | 'config/**/*.js', 28 | 'tests/dummy/config/**/*.js' 29 | ], 30 | excludedFiles: [ 31 | 'addon/**', 32 | 'addon-test-support/**', 33 | 'app/**', 34 | 'tests/dummy/app/**' 35 | ], 36 | parserOptions: { 37 | sourceType: 'script', 38 | ecmaVersion: 2015 39 | }, 40 | env: { 41 | browser: false, 42 | node: true 43 | }, 44 | plugins: ['node'], 45 | rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, { 46 | // add your custom rules and overrides for node files here 47 | }) 48 | } 49 | ] 50 | }; 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist/ 5 | /tmp/ 6 | 7 | # dependencies 8 | /bower_components/ 9 | /node_modules/ 10 | 11 | # misc 12 | /.sass-cache 13 | /connect.lock 14 | !/coverage/coverage-summary.json 15 | /coverage/ 16 | /libpeerconnection.log 17 | /npm-debug.log* 18 | /testem.log 19 | /yarn-error.log 20 | 21 | # ember-try 22 | /.node_modules.ember-try/ 23 | /bower.json.ember-try 24 | /package.json.ember-try 25 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /bower_components 2 | /config/ember-try.js 3 | /dist 4 | /tests 5 | /tmp 6 | **/.gitkeep 7 | .bowerrc 8 | .editorconfig 9 | .ember-cli 10 | .eslintrc.js 11 | .gitignore 12 | .watchmanconfig 13 | .travis.yml 14 | bower.json 15 | ember-cli-build.js 16 | testem.js 17 | yarn.lock 18 | 19 | # ember-try 20 | .node_modules.ember-try/ 21 | bower.json.ember-try 22 | package.json.ember-try 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | node_js: 4 | # we recommend testing addons with the same minimum supported node version as Ember CLI 5 | # so that your addon works for all apps 6 | - "6" 7 | 8 | sudo: false 9 | dist: trusty 10 | 11 | addons: 12 | chrome: stable 13 | 14 | cache: 15 | directories: 16 | - $HOME/.npm 17 | 18 | env: 19 | global: 20 | # See https://git.io/vdao3 for details. 21 | - JOBS=1 22 | matrix: 23 | # we recommend new addons test the current and previous LTS 24 | # as well as latest stable release (bonus points to beta/canary) 25 | - EMBER_TRY_SCENARIO=ember-lts-2.12 26 | - EMBER_TRY_SCENARIO=ember-lts-2.16 27 | - EMBER_TRY_SCENARIO=ember-lts-2.18 28 | - EMBER_TRY_SCENARIO=ember-release 29 | - EMBER_TRY_SCENARIO=ember-beta 30 | - EMBER_TRY_SCENARIO=ember-canary 31 | - EMBER_TRY_SCENARIO=ember-default 32 | 33 | matrix: 34 | fast_finish: true 35 | allow_failures: 36 | - env: EMBER_TRY_SCENARIO=ember-canary 37 | 38 | before_install: 39 | - npm config set spin false 40 | - npm install -g npm@4 41 | - npm --version 42 | 43 | install: 44 | - npm install 45 | 46 | script: 47 | - npm run lint:js 48 | # Usually, it's ok to finish the test scenario without reverting 49 | # to the addon's original dependency state, skipping "cleanup". 50 | - npm test 51 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ========= 3 | 4 | - [Fix .get() for sometimes condition with falsy values](https://github.com/skaterdav85/ember-changeset-conditional-validations/pull/16) 5 | - Upgrades `ember-sinon` 6 | 7 | ## 0.6.0 8 | 9 | ## 0.4.2 10 | 11 | - Fixes https://github.com/skaterdav85/ember-changeset-conditional-validations/issues/10 12 | - Clean up tests 13 | - Update via ember-cli-update 14 | 15 | ## 0.2.0 16 | 17 | - Upgrades Ember CLI 18 | - Switch PhantomJS to headless Chrome 19 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/skaterdav85/ember-changeset-conditional-validations.svg?branch=master)](https://travis-ci.org/skaterdav85/ember-changeset-conditional-validations) [![Ember Observer Score](https://emberobserver.com/badges/ember-changeset-conditional-validations.svg)](https://emberobserver.com/addons/ember-changeset-conditional-validations) 2 | 3 | # ember-changeset-conditional-validations 4 | 5 | An extra validator for conditional validations with [`ember-changeset-validations`](https://github.com/DockYard/ember-changeset-validations). 6 | 7 | ## Installation 8 | 9 | ``` 10 | ember install ember-changeset-conditional-validations 11 | ``` 12 | 13 | ## Basic Usage 14 | 15 | Let's say you want to validate a user's settings. Only if the payment method is a credit card should the credit card number validations be applied. 16 | 17 | ```js 18 | import { validatePresence, validateLength } from 'ember-changeset-validations/validators'; 19 | import validateSometimes from 'ember-changeset-conditional-validations/validators/sometimes'; 20 | 21 | export default { 22 | creditCardNumber: validateSometimes([ 23 | validatePresence(true), 24 | validateLength({ is: 16 }) 25 | ], function(changes, content) { 26 | return this.get('paymentMethod.isCreditCard'); 27 | }) 28 | }; 29 | ``` 30 | 31 | `validateSometimes()` takes 2 arguments. The first is a validator or an array of validators you want applied to the attribute. The second argument is a callback function which represents the condition. If the condition callback returns `true`, the rules will be added. This callback function will be invoked with the changeset's changes and content. The callback will also be invoked with its `this` value set to an object that has a `get()` method for accessing a property. `this.get(property)` first proxies to the changes and then the underlying content, and has the same semantics as `Ember.get()`. 32 | 33 | ```js 34 | import Changeset from 'ember-changeset'; 35 | import lookupValidator from 'ember-changeset-validations'; 36 | import Validations from './../validations/settings'; 37 | 38 | let settings = {}; 39 | let changeset = new Changeset(settings, lookupValidator(Validations), Validations); 40 | 41 | console.log(changeset.get('isValid')); // true 42 | changeset.set('paymentMethod', { 43 | isCreditCard: true 44 | }); 45 | changeset.validate(); 46 | console.log(changeset.get('isValid')); // false 47 | console.log(changeset.get('errors')); // [{key: 'creditCardNumber', validation: ['Credit card number can't be blank', 'Credit card number must be a number']}] 48 | changeset.set('creditCardNumber', '1234567890123456'); 49 | changeset.validate(); 50 | console.log(changeset.get('isValid')); // true 51 | changeset.set('creditCardNumber', '1234'); 52 | changeset.validate(); 53 | console.log(changeset.get('isValid')); // false 54 | console.log(changeset.get('errors')); // [{key: 'creditCardNumber', value: '1234', validation: ['Credit card number must be equal to 16']}] 55 | changeset.set('paymentMethod', { 56 | isCreditCard: false 57 | }); 58 | changeset.validate(); 59 | console.log(changeset.get('isValid')); // true 60 | ``` 61 | 62 | ### Combining Validations with Conditional Validations 63 | 64 | You can also have a combination of validations that will always run and conditional validations. For example, say you wanted to validate that a property is a number, but conditionally validate that the number is greater than 5. You could do something like the following: 65 | 66 | ```js 67 | import { validateNumber } from 'ember-changeset-validations/validators'; 68 | import validateSometimes from 'ember-changeset-conditional-validations/validators/sometimes'; 69 | 70 | export default { 71 | someProperty: [ 72 | validateNumber({ integer: true }), 73 | validateSometimes(validateNumber({ gt: 5 }), function() { 74 | // condition 75 | }) 76 | ] 77 | }; 78 | ``` 79 | 80 | Let's say in the previous example that you also wanted to conditionally validate that the number is less than 10. You could do something like the following: 81 | 82 | ```js 83 | import { validateNumber } from 'ember-changeset-validations/validators'; 84 | import validateSometimes from 'ember-changeset-conditional-validations/validators/sometimes'; 85 | 86 | export default { 87 | someProperty: [ 88 | validateNumber({ integer: true }), 89 | ...validateSometimes([ 90 | validateNumber({ gt: 5 }), 91 | validateNumber({ lt: 10 }) 92 | ], function() { 93 | // condition 94 | }) 95 | ] 96 | }; 97 | ``` 98 | 99 | ## Installation 100 | 101 | * `git clone ` this repository 102 | * `cd ember-changeset-conditional-validations` 103 | * `npm install` 104 | 105 | ## Running 106 | 107 | * `ember serve` 108 | * Visit your app at [http://localhost:4200](http://localhost:4200). 109 | 110 | ## Running Tests 111 | 112 | * `npm test` (Runs `ember try:each` to test your addon against multiple Ember versions) 113 | * `ember test` 114 | * `ember test --server` 115 | 116 | ## Building 117 | 118 | * `ember build` 119 | 120 | For more information on using ember-cli, visit [https://ember-cli.com/](https://ember-cli.com/). 121 | -------------------------------------------------------------------------------- /addon/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/addon/.gitkeep -------------------------------------------------------------------------------- /addon/validators/sometimes.js: -------------------------------------------------------------------------------- 1 | import { get } from '@ember/object'; 2 | 3 | export default function validateSometimes(validator, condition) { 4 | if (Array.isArray(arguments[0])) { 5 | let validators = arguments[0]; 6 | return validators.map(guardValidatorWithCondition); 7 | } else { 8 | let validator = arguments[0]; 9 | return guardValidatorWithCondition(validator); 10 | } 11 | 12 | function guardValidatorWithCondition(validator) { 13 | return function(key, newValue, oldValue, changes, content) { 14 | let thisValue = { 15 | get(property) { 16 | if (property.includes('.')) { 17 | let changesValue = get(changes, property); 18 | if (typeof changesValue !== 'undefined') { 19 | return changesValue; 20 | } 21 | 22 | // Check if the `changes` value is explicitly undefined, 23 | // or if it's not present at all. 24 | let pathSegments = property.split('.'); 25 | let propName = pathSegments.pop(); 26 | let objPath = pathSegments.join('.'); 27 | 28 | let obj = get(changes, objPath); 29 | if (obj && obj.hasOwnProperty && obj.hasOwnProperty(propName)) { 30 | return changesValue; 31 | } 32 | 33 | return get(content, property); 34 | } 35 | 36 | if (changes.hasOwnProperty(property)) { 37 | return get(changes, property); 38 | } else { 39 | return get(content, property); 40 | } 41 | } 42 | }; 43 | 44 | if (condition.call(thisValue, changes, content)) { 45 | return validator(key, newValue, oldValue, changes, content); 46 | } 47 | return true; 48 | }; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/app/.gitkeep -------------------------------------------------------------------------------- /config/ember-try.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const getChannelURL = require('ember-source-channel-url'); 4 | 5 | module.exports = function() { 6 | return Promise.all([ 7 | getChannelURL('release'), 8 | getChannelURL('beta'), 9 | getChannelURL('canary') 10 | ]).then((urls) => { 11 | return { 12 | scenarios: [ 13 | { 14 | name: 'ember-lts-2.12', 15 | npm: { 16 | devDependencies: { 17 | 'ember-source': '~2.12.0' 18 | } 19 | } 20 | }, 21 | { 22 | name: 'ember-lts-2.16', 23 | npm: { 24 | devDependencies: { 25 | 'ember-source': '~2.16.0' 26 | } 27 | } 28 | }, 29 | { 30 | name: 'ember-lts-2.18', 31 | npm: { 32 | devDependencies: { 33 | 'ember-source': '~2.18.0' 34 | } 35 | } 36 | }, 37 | { 38 | name: 'ember-release', 39 | npm: { 40 | devDependencies: { 41 | 'ember-source': urls[0] 42 | } 43 | } 44 | }, 45 | { 46 | name: 'ember-beta', 47 | npm: { 48 | devDependencies: { 49 | 'ember-source': urls[1] 50 | } 51 | } 52 | }, 53 | { 54 | name: 'ember-canary', 55 | npm: { 56 | devDependencies: { 57 | 'ember-source': urls[2] 58 | } 59 | } 60 | }, 61 | { 62 | name: 'ember-default', 63 | npm: { 64 | devDependencies: {} 65 | } 66 | } 67 | ] 68 | }; 69 | }); 70 | }; 71 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(/* environment, appConfig */) { 4 | return { }; 5 | }; 6 | -------------------------------------------------------------------------------- /coverage/coverage-summary.json: -------------------------------------------------------------------------------- 1 | { 2 | "total":{"lines":{"total":28,"covered":27,"skipped":0,"pct":96.43},"statements":{"total":28,"covered":27,"skipped":0,"pct":96.43},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"branches":{"total":15,"covered":12,"skipped":0,"pct":80},"linesCovered":{"3":1,"4":15,"5":13,"6":14,"8":2,"9":2,"12":2,"13":28,"14":57,"16":48,"17":22,"18":22,"19":4,"24":18,"25":18,"26":18,"28":18,"29":18,"30":0,"33":18,"36":26,"37":20,"39":6,"44":57,"45":25,"47":32}}, 3 | "tests/dummy/app/resolver.js":{"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100},"linesCovered":{}}, 4 | "tests/dummy/app/app.js":{"lines":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":2,"covered":2,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100},"linesCovered":{"6":1,"12":1}}, 5 | "addon/validators/sometimes.js":{"lines":{"total":26,"covered":25,"skipped":0,"pct":96.15},"statements":{"total":26,"covered":25,"skipped":0,"pct":96.15},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"branches":{"total":15,"covered":12,"skipped":0,"pct":80},"linesCovered":{"3":1,"4":15,"5":13,"6":13,"8":2,"9":2,"12":1,"13":28,"14":57,"16":48,"17":22,"18":22,"19":4,"24":18,"25":18,"26":18,"28":18,"29":18,"30":0,"33":18,"36":26,"37":20,"39":6,"44":57,"45":25,"47":32}}} 6 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); 4 | 5 | module.exports = function(defaults) { 6 | let app = new EmberAddon(defaults, { 7 | // Add options here 8 | }); 9 | 10 | /* 11 | This build file specifies the options for the dummy test app of this 12 | addon, located in `/tests/dummy` 13 | This build file does *not* influence how the addon or the app using it 14 | behave. You most likely want to be modifying `./index.js` or app's build file 15 | */ 16 | 17 | return app.toTree(); 18 | }; 19 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | name: 'ember-changeset-conditional-validations' 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-changeset-conditional-validations", 3 | "version": "0.6.0", 4 | "description": "Conditional validations for ember-changeset-validations", 5 | "keywords": [ 6 | "ember-addon", 7 | "ember-changeset", 8 | "ember-changeset-validations", 9 | "changeset", 10 | "validations", 11 | "conditional validations" 12 | ], 13 | "repository": "https://github.com/skaterdav85/ember-changeset-conditional-validations", 14 | "license": "MIT", 15 | "author": "David Tang ", 16 | "directories": { 17 | "doc": "doc", 18 | "test": "tests" 19 | }, 20 | "bugs": "https://github.com/skaterdav85/ember-changeset-conditional-validations/issues", 21 | "homepage": "https://github.com/skaterdav85/ember-changeset-conditional-validations", 22 | "scripts": { 23 | "build": "ember build", 24 | "lint:js": "eslint .", 25 | "start": "ember serve", 26 | "test": "ember test", 27 | "test:all": "ember try:each", 28 | "test-with-coverage": "COVERAGE=true ember test -s" 29 | }, 30 | "dependencies": { 31 | "ember-cli-babel": "^6.16.0" 32 | }, 33 | "devDependencies": { 34 | "broccoli-asset-rev": "^2.7.0", 35 | "ember-changeset": "^1.3.0", 36 | "ember-changeset-validations": "^1.2.8", 37 | "ember-cli": "~3.3.0", 38 | "ember-cli-code-coverage": "^0.4.2", 39 | "ember-cli-dependency-checker": "^2.0.0", 40 | "ember-cli-doorkeeper": "^0.1.4", 41 | "ember-cli-eslint": "^4.2.1", 42 | "ember-cli-htmlbars": "^2.0.1", 43 | "ember-cli-htmlbars-inline-precompile": "^1.0.0", 44 | "ember-cli-inject-live-reload": "^1.4.1", 45 | "ember-cli-qunit": "^4.3.2", 46 | "ember-cli-shims": "^1.2.0", 47 | "ember-cli-sri": "^2.1.0", 48 | "ember-cli-uglify": "^1.2.0", 49 | "ember-disable-prototype-extensions": "^1.1.2", 50 | "ember-export-application-global": "^2.0.0", 51 | "ember-load-initializers": "^1.1.0", 52 | "ember-maybe-import-regenerator": "^0.1.6", 53 | "ember-resolver": "^4.0.0", 54 | "ember-sinon": "^5.0.0", 55 | "ember-source": "~3.3.0", 56 | "ember-source-channel-url": "^1.0.1", 57 | "ember-try": "^0.2.23", 58 | "eslint-plugin-ember": "^5.0.0", 59 | "eslint-plugin-node": "^6.0.1", 60 | "loader.js": "^4.2.3", 61 | "qunit-dom": "^0.6.2" 62 | }, 63 | "engines": { 64 | "node": "6.* || 8.* || >= 10.*" 65 | }, 66 | "ember-addon": { 67 | "configPath": "tests/dummy/config" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /testem.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | test_page: 'tests/index.html?hidepassed', 3 | disable_watching: true, 4 | launch_in_ci: [ 5 | 'Chrome' 6 | ], 7 | launch_in_dev: [ 8 | 'Chrome' 9 | ], 10 | browser_args: { 11 | Chrome: { 12 | ci: [ 13 | // --no-sandbox is needed when running Chrome inside a container 14 | process.env.CI ? '--no-sandbox' : null, 15 | '--headless', 16 | '--disable-gpu', 17 | '--disable-dev-shm-usage', 18 | '--disable-software-rasterizer', 19 | '--mute-audio', 20 | '--remote-debugging-port=0', 21 | '--window-size=1440,900' 22 | ].filter(Boolean) 23 | } 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /tests/dummy/app/app.js: -------------------------------------------------------------------------------- 1 | import Application from '@ember/application'; 2 | import Resolver from './resolver'; 3 | import loadInitializers from 'ember-load-initializers'; 4 | import config from './config/environment'; 5 | 6 | const App = Application.extend({ 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix, 9 | Resolver 10 | }); 11 | 12 | loadInitializers(App, config.modulePrefix); 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /tests/dummy/app/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/tests/dummy/app/components/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/tests/dummy/app/controllers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/controllers/application.js: -------------------------------------------------------------------------------- 1 | import Controller from '@ember/controller'; 2 | import Changeset from 'ember-changeset'; 3 | import lookupValidator from 'ember-changeset-validations'; 4 | import Validations from './../validations/settings'; 5 | 6 | export default Controller.extend({ 7 | init() { 8 | this._super(...arguments); 9 | let settings = {}; 10 | let changeset = new Changeset(settings, lookupValidator(Validations), Validations); 11 | this.set('changeset', changeset); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /tests/dummy/app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/tests/dummy/app/helpers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dummy 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | 12 | 13 | 14 | 15 | {{content-for "head-footer"}} 16 | 17 | 18 | {{content-for "body"}} 19 | 20 | 21 | 22 | 23 | {{content-for "body-footer"}} 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/dummy/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/tests/dummy/app/models/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from 'ember-resolver'; 2 | 3 | export default Resolver; 4 | -------------------------------------------------------------------------------- /tests/dummy/app/router.js: -------------------------------------------------------------------------------- 1 | import EmberRouter from '@ember/routing/router'; 2 | import config from './config/environment'; 3 | 4 | const Router = EmberRouter.extend({ 5 | location: config.locationType, 6 | rootURL: config.rootURL 7 | }); 8 | 9 | Router.map(function() { 10 | }); 11 | 12 | export default Router; 13 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/tests/dummy/app/routes/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/tests/dummy/app/styles/app.css -------------------------------------------------------------------------------- /tests/dummy/app/templates/application.hbs: -------------------------------------------------------------------------------- 1 | Valid?: {{changeset.isValid}} 2 |
3 | Payment Method*: 4 | {{changeset.paymentMethod}} 5 |
6 | Paypal: 11 | Credit Card: 16 |
17 | Credit Card Number: {{changeset.creditCardNumber}} 18 |
19 | 23 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/tests/dummy/app/templates/components/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/validations/settings.js: -------------------------------------------------------------------------------- 1 | import { validatePresence, validateLength } from 'ember-changeset-validations/validators'; 2 | import validateSometimes from 'ember-changeset-conditional-validations/validators/sometimes'; 3 | 4 | export default { 5 | paymentMethod: validatePresence(true), 6 | creditCardNumber: validateSometimes([ 7 | validatePresence(true), 8 | validateLength({ is: 16 }) 9 | ], function() { 10 | return this.get('paymentMethod') === 'credit-card'; 11 | }) 12 | }; 13 | -------------------------------------------------------------------------------- /tests/dummy/config/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(environment) { 4 | let ENV = { 5 | modulePrefix: 'dummy', 6 | environment, 7 | rootURL: '/', 8 | locationType: 'auto', 9 | EmberENV: { 10 | FEATURES: { 11 | // Here you can enable experimental features on an ember canary build 12 | // e.g. 'with-controller': true 13 | }, 14 | EXTEND_PROTOTYPES: { 15 | // Prevent Ember Data from overriding Date.parse. 16 | Date: false 17 | } 18 | }, 19 | 20 | APP: { 21 | // Here you can pass flags/options to your application instance 22 | // when it is created 23 | } 24 | }; 25 | 26 | if (environment === 'development') { 27 | // ENV.APP.LOG_RESOLVER = true; 28 | // ENV.APP.LOG_ACTIVE_GENERATION = true; 29 | // ENV.APP.LOG_TRANSITIONS = true; 30 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 31 | // ENV.APP.LOG_VIEW_LOOKUPS = true; 32 | } 33 | 34 | if (environment === 'test') { 35 | // Testem prefers this... 36 | ENV.locationType = 'none'; 37 | 38 | // keep test console output quieter 39 | ENV.APP.LOG_ACTIVE_GENERATION = false; 40 | ENV.APP.LOG_VIEW_LOOKUPS = false; 41 | 42 | ENV.APP.rootElement = '#ember-testing'; 43 | ENV.APP.autoboot = false; 44 | } 45 | 46 | return ENV; 47 | }; 48 | -------------------------------------------------------------------------------- /tests/dummy/config/targets.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const browsers = [ 4 | 'last 1 Chrome versions', 5 | 'last 1 Firefox versions', 6 | 'last 1 Safari versions' 7 | ]; 8 | 9 | const isCI = !!process.env.CI; 10 | const isProduction = process.env.EMBER_ENV === 'production'; 11 | 12 | if (isCI || isProduction) { 13 | browsers.push('ie 11'); 14 | } 15 | 16 | module.exports = { 17 | browsers 18 | }; 19 | -------------------------------------------------------------------------------- /tests/dummy/public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /tests/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/tests/helpers/.gitkeep -------------------------------------------------------------------------------- /tests/helpers/destroy-app.js: -------------------------------------------------------------------------------- 1 | import { run } from '@ember/runloop'; 2 | 3 | export default function destroyApp(application) { 4 | run(application, 'destroy'); 5 | } 6 | -------------------------------------------------------------------------------- /tests/helpers/is-function.js: -------------------------------------------------------------------------------- 1 | import { typeOf } from '@ember/utils'; 2 | 3 | export default function isFunction(fn) { 4 | return typeOf(fn) === 'function'; 5 | } 6 | -------------------------------------------------------------------------------- /tests/helpers/module-for-acceptance.js: -------------------------------------------------------------------------------- 1 | import { resolve } from 'rsvp'; 2 | import { module } from 'qunit'; 3 | import startApp from '../helpers/start-app'; 4 | import destroyApp from '../helpers/destroy-app'; 5 | 6 | export default function(name, options = {}) { 7 | module(name, { 8 | beforeEach() { 9 | this.application = startApp(); 10 | 11 | if (options.beforeEach) { 12 | return options.beforeEach.apply(this, arguments); 13 | } 14 | }, 15 | 16 | afterEach() { 17 | let afterEach = options.afterEach && options.afterEach.apply(this, arguments); 18 | return resolve(afterEach).then(() => destroyApp(this.application)); 19 | } 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /tests/helpers/start-app.js: -------------------------------------------------------------------------------- 1 | import { run } from '@ember/runloop'; 2 | import { merge } from '@ember/polyfills'; 3 | import Application from '../../app'; 4 | import config from '../../config/environment'; 5 | 6 | export default function startApp(attrs) { 7 | let attributes = merge({}, config.APP); 8 | attributes = merge(attributes, attrs); // use defaults, but you can override; 9 | 10 | return run(() => { 11 | let application = Application.create(attributes); 12 | application.setupForTesting(); 13 | application.injectTestHelpers(); 14 | return application; 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dummy Tests 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | {{content-for "test-head"}} 12 | 13 | 14 | 15 | 16 | 17 | {{content-for "head-footer"}} 18 | {{content-for "test-head-footer"}} 19 | 20 | 21 | {{content-for "body"}} 22 | {{content-for "test-body"}} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {{content-for "body-footer"}} 31 | {{content-for "test-body-footer"}} 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/integration/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/tests/integration/.gitkeep -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import Application from '../app'; 2 | import config from '../config/environment'; 3 | import { setApplication } from '@ember/test-helpers'; 4 | import { start } from 'ember-qunit'; 5 | 6 | setApplication(Application.create(config.APP)); 7 | 8 | start(); 9 | -------------------------------------------------------------------------------- /tests/unit/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/tests/unit/.gitkeep -------------------------------------------------------------------------------- /tests/unit/validators/sometimes-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { validatePresence, validateLength } from 'ember-changeset-validations/validators'; 3 | import validateSometimes from 'ember-changeset-conditional-validations/validators/sometimes'; 4 | import lookupValidator from 'ember-changeset-validations'; 5 | import sinon from 'sinon'; 6 | import isFunction from './../../helpers/is-function'; 7 | import Changeset from 'ember-changeset'; 8 | 9 | module('Unit | Validator | sometimes', function() { 10 | test('an array of validators is returned when given an array', function(assert) { 11 | let validatorA = function() {}; 12 | let validatorB = function() {}; 13 | let condition = function() {}; 14 | 15 | let validators = validateSometimes([validatorA, validatorB], condition); 16 | 17 | assert.equal(validators.length, 2); 18 | assert.ok(validators.every(isFunction)); 19 | }); 20 | 21 | test('a validator function is returned if given a validator', function(assert) { 22 | let validatorA = function() {}; 23 | let condition = function() {}; 24 | 25 | let validator = validateSometimes(validatorA, condition); 26 | 27 | assert.ok(isFunction(validator)); 28 | }); 29 | 30 | test('if the condition returns false, the validators return true', function(assert) { 31 | let validatorA = function() {}; 32 | let validatorB = function() {}; 33 | let condition = () => false; 34 | 35 | let validators = validateSometimes([validatorA, validatorB], condition); 36 | let validations = validators.map(validator => validator()); 37 | 38 | assert.deepEqual(validations, [true, true]); 39 | }); 40 | 41 | test('if the condition returns true, the validators are invoked and their result is returned', function(assert) { 42 | let validatorA = () => 'Error message A'; 43 | let validatorB = () => true; 44 | let condition = () => true; 45 | 46 | let validators = validateSometimes([validatorA, validatorB], condition); 47 | let validations = validators.map(validator => validator()); 48 | 49 | assert.deepEqual(validations, ['Error message A', true]); 50 | }); 51 | 52 | test('the condition is invoked with the changes and content for each validator', function(assert) { 53 | let key = 'name'; 54 | let newValue = 'Yehuda'; 55 | let oldValue = 'YK'; 56 | let changes = {}; 57 | let content = {}; 58 | 59 | let validatorA = () => 'Error message A'; 60 | let validatorB = () => true; 61 | let condition = sinon.spy(); 62 | 63 | let validators = validateSometimes([validatorA, validatorB], condition); 64 | validators.forEach((validator) => { 65 | return validator(key, newValue, oldValue, changes, content); 66 | }); 67 | 68 | assert.equal(condition.callCount, 2); 69 | assert.strictEqual(condition.getCall(0).args[0], changes); 70 | assert.strictEqual(condition.getCall(0).args[1], content); 71 | assert.strictEqual(condition.getCall(1).args[0], changes); 72 | assert.strictEqual(condition.getCall(1).args[1], content); 73 | }); 74 | 75 | test('each validator is invoked with key, newValue, oldValue, changes, and content', function(assert) { 76 | let key = 'name'; 77 | let newValue = 'Yehuda'; 78 | let oldValue = 'YK'; 79 | let changes = {}; 80 | let content = {}; 81 | 82 | let validatorA = sinon.spy(); 83 | let validatorB = sinon.spy(); 84 | let condition = () => true; 85 | 86 | let validators = validateSometimes([validatorA, validatorB], condition); 87 | validators.forEach((validator) => { 88 | return validator(key, newValue, oldValue, changes, content); 89 | }); 90 | 91 | assert.strictEqual(validatorA.firstCall.args[0], key); 92 | assert.strictEqual(validatorA.firstCall.args[1], newValue); 93 | assert.strictEqual(validatorA.firstCall.args[2], oldValue); 94 | assert.strictEqual(validatorA.firstCall.args[3], changes); 95 | assert.strictEqual(validatorA.firstCall.args[4], content); 96 | assert.strictEqual(validatorB.firstCall.args[0], key); 97 | assert.strictEqual(validatorB.firstCall.args[1], newValue); 98 | assert.strictEqual(validatorB.firstCall.args[2], oldValue); 99 | assert.strictEqual(validatorB.firstCall.args[3], changes); 100 | assert.strictEqual(validatorB.firstCall.args[4], content); 101 | }); 102 | 103 | test('single validator is invoked with key, newValue, oldValue, changes, and content', function(assert) { 104 | let key = 'name'; 105 | let newValue = 'Yehuda'; 106 | let oldValue = 'YK'; 107 | let changes = {}; 108 | let content = {}; 109 | 110 | let validatorA = sinon.spy(); 111 | let condition = () => true; 112 | 113 | let validator = validateSometimes(validatorA, condition); 114 | 115 | assert.ok(isFunction(validator)); 116 | 117 | validator(key, newValue, oldValue, changes, content); 118 | 119 | assert.strictEqual(validatorA.firstCall.args[0], key); 120 | assert.strictEqual(validatorA.firstCall.args[1], newValue); 121 | assert.strictEqual(validatorA.firstCall.args[2], oldValue); 122 | assert.strictEqual(validatorA.firstCall.args[3], changes); 123 | assert.strictEqual(validatorA.firstCall.args[4], content); 124 | }); 125 | 126 | test('this.get() when accessing the changes', function(assert) { 127 | let Validations = { 128 | paymentMethod: validatePresence(true), 129 | creditCardNumber: validateSometimes([ 130 | validatePresence(true), 131 | validateLength({ is: 16 }) 132 | ], function() { 133 | return this.get('paymentMethod') === 'credit-card'; 134 | }) 135 | }; 136 | 137 | let changeset = new Changeset({}, lookupValidator(Validations), Validations); 138 | changeset.set('paymentMethod', 'credit-card'); 139 | changeset.set('creditCardNumber', '12'); 140 | changeset.validate(); 141 | 142 | assert.notOk(changeset.get('isValid'), 'invalid'); 143 | 144 | changeset.set('creditCardNumber', '1234567890123456'); 145 | changeset.validate(); 146 | 147 | assert.ok(changeset.get('isValid'), 'valid'); 148 | }); 149 | 150 | test('this.get() when accessing the content', function(assert) { 151 | let Validations = { 152 | paymentMethod: validatePresence(true), 153 | creditCardNumber: validateSometimes([ 154 | validatePresence(true), 155 | validateLength({ is: 16 }) 156 | ], function() { 157 | return this.get('paymentMethod') === 'credit-card'; 158 | }) 159 | }; 160 | 161 | let changeset = new Changeset({ 162 | paymentMethod: 'credit-card' 163 | }, lookupValidator(Validations), Validations); 164 | 165 | changeset.set('creditCardNumber', '12'); 166 | changeset.validate(); 167 | 168 | assert.notOk(changeset.get('isValid'), 'invalid'); 169 | 170 | changeset.set('creditCardNumber', '1234567890123456'); 171 | 172 | assert.ok(changeset.get('isValid'), 'valid'); 173 | }); 174 | 175 | test('this.get() when accessing content with a property path', function(assert) { 176 | let Validations = { 177 | paymentMethod: validatePresence(true), 178 | creditCardNumber: validateSometimes([ 179 | validatePresence(true), 180 | validateLength({ is: 16 }) 181 | ], function() { 182 | return this.get('paymentMethod.isCreditCard'); 183 | }) 184 | }; 185 | 186 | let changeset = new Changeset({ 187 | paymentMethod: { 188 | isCreditCard: true 189 | }, 190 | creditCardNumber: 12 191 | }, lookupValidator(Validations), Validations); 192 | changeset.validate(); 193 | 194 | assert.notOk(changeset.get('isValid')); 195 | }); 196 | 197 | test('this.get() when accessing changes with a property path', function(assert) { 198 | let Validations = { 199 | paymentMethod: validatePresence(true), 200 | creditCardNumber: validateSometimes([ 201 | validatePresence(true), 202 | validateLength({ is: 16 }) 203 | ], function() { 204 | return this.get('paymentMethod.isCreditCard'); 205 | }) 206 | }; 207 | 208 | let changeset = new Changeset({}, lookupValidator(Validations), Validations); 209 | changeset.set('paymentMethod', { 210 | isCreditCard: true 211 | }); 212 | changeset.set('creditCardNumber', '12'); 213 | changeset.validate(); 214 | 215 | assert.notOk(changeset.get('isValid')); 216 | }); 217 | 218 | test('this.get() when setting the value to false', function(assert) { 219 | let Validations = { 220 | hasCreditCard: validatePresence(true), 221 | creditCardNumber: validateSometimes([ 222 | validatePresence(true), 223 | validateLength({ is: 16 }) 224 | ], function () { 225 | return this.get('hasCreditCard'); 226 | }) 227 | }; 228 | 229 | let changeset = new Changeset({ 230 | hasCreditCard: true 231 | }, lookupValidator(Validations), Validations); 232 | 233 | changeset.set('hasCreditCard', false); 234 | changeset.set('creditCardNumber', '12'); 235 | changeset.validate(); 236 | 237 | assert.ok(changeset.get('isValid'), 'valid'); 238 | }); 239 | 240 | test('this.get() when setting the value to null', function(assert) { 241 | let Validations = { 242 | creditCardNumber: validateSometimes([ 243 | validatePresence(true), 244 | validateLength({ is: 16 }) 245 | ], function () { 246 | return this.get('creditCardDetails'); 247 | }) 248 | }; 249 | 250 | let changeset = new Changeset({ 251 | creditCardDetails: { 252 | number: '1234567890123456' 253 | } 254 | }, lookupValidator(Validations), Validations); 255 | 256 | changeset.set('creditCardDetails', null); 257 | changeset.set('creditCardNumber', '12'); 258 | changeset.validate(); 259 | 260 | assert.ok(changeset.get('isValid'), 'valid'); 261 | }); 262 | 263 | test('this.get() when setting the value to undefined', function(assert) { 264 | let Validations = { 265 | creditCardNumber: validateSometimes([ 266 | validatePresence(true), 267 | validateLength({ is: 16 }) 268 | ], function () { 269 | return this.get('creditCardDetails'); 270 | }) 271 | }; 272 | 273 | let changeset = new Changeset({ 274 | creditCardDetails: { 275 | number: '1234567890123456' 276 | } 277 | }, lookupValidator(Validations), Validations); 278 | 279 | changeset.set('creditCardDetails', undefined); 280 | changeset.set('creditCardNumber', '12'); 281 | changeset.validate(); 282 | 283 | assert.ok(changeset.get('isValid'), 'valid'); 284 | }); 285 | 286 | test('this.get() when setting a property path to falsy values', function(assert) { 287 | let Validations = { 288 | creditCardNumber: validateSometimes([ 289 | validatePresence(true), 290 | validateLength({ is: 16 }) 291 | ], function() { 292 | return this.get('paymentMethod.isCreditCard'); 293 | }) 294 | }; 295 | 296 | let changeset = new Changeset({ 297 | paymentDetails: { 298 | methodInfo: { 299 | isCreditCard: true 300 | } 301 | }, 302 | creditCardNumber: 12 303 | }, lookupValidator(Validations), Validations); 304 | 305 | changeset.validate(); 306 | assert.ok(changeset.get('isValid')); 307 | 308 | changeset.set('paymentDetails.methodInfo.isCreditCard', false); 309 | changeset.validate(); 310 | assert.ok(changeset.get('isValid')); 311 | 312 | changeset.set('paymentDetails.methodInfo.isCreditCard', null); 313 | changeset.validate(); 314 | assert.ok(changeset.get('isValid')); 315 | 316 | changeset.set('paymentDetails.methodInfo.isCreditCard', undefined); 317 | changeset.validate(); 318 | assert.ok(changeset.get('isValid')); 319 | 320 | changeset.set('paymentDetails.methodInfo', null); 321 | changeset.validate(); 322 | assert.ok(changeset.get('isValid')); 323 | 324 | changeset.set('paymentDetails.methodInfo', undefined); 325 | changeset.validate(); 326 | assert.ok(changeset.get('isValid')); 327 | 328 | changeset.set('paymentDetails', null); 329 | changeset.validate(); 330 | assert.ok(changeset.get('isValid')); 331 | 332 | changeset.set('paymentDetails', undefined); 333 | changeset.validate(); 334 | assert.ok(changeset.get('isValid')); 335 | }); 336 | }); 337 | -------------------------------------------------------------------------------- /vendor/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamdtang/ember-changeset-conditional-validations/79bf6bf069e6be99bd3a2ccf2bdcd47795f33683/vendor/.gitkeep --------------------------------------------------------------------------------