diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89868b47..c12905f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: - name: Install Node uses: actions/setup-node@v3 with: - node-version: 14.x + node-version: 16.x cache: yarn - name: Install Dependencies run: yarn install --frozen-lockfile --ignore-engines @@ -40,7 +40,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 14.x + node-version: 16.x cache: yarn - name: Install Dependencies run: yarn install --no-lockfile --ignore-engines @@ -72,7 +72,7 @@ jobs: - name: Install Node uses: actions/setup-node@v3 with: - node-version: 14.x + node-version: 16.x cache: yarn - name: Install Dependencies run: yarn install --frozen-lockfile --ignore-engines diff --git a/addon/utils/utils.js b/addon/utils/utils.js index e600308a..1989a6fc 100644 --- a/addon/utils/utils.js +++ b/addon/utils/utils.js @@ -4,6 +4,8 @@ import { isHTMLSafe } from '@ember/template'; import EmberObject from '@ember/object'; import { typeOf } from '@ember/utils'; import { A as emberArray } from '@ember/array'; + +// ember-data feature detection import { macroCondition, dependencySatisfies, @@ -17,6 +19,19 @@ if (macroCondition(dependencySatisfies('ember-data', '*'))) { Model = importSync('@ember-data/model').default; } +export function isDsModel(o) { + return !!(Model && o && o instanceof Model); +} + +export function isDSManyArray(o) { + return !!( + DS && + o && + (o instanceof DS.PromiseManyArray || o instanceof DS.ManyArray) + ); +} + +// ember internals export { getDependentKeys, isDescriptor } from '../-private/ember-internals'; export function unwrapString(s) { @@ -45,18 +60,6 @@ export function isPromise(p) { return !!(p && canInvoke(p, 'then')); } -export function isDsModel(o) { - return !!(Model && o && o instanceof Model); -} - -export function isDSManyArray(o) { - return !!( - DS && - o && - (o instanceof DS.PromiseManyArray || o instanceof DS.ManyArray) - ); -} - export function isEmberObject(o) { return !!(o && o instanceof EmberObject); } diff --git a/tests/integration/validations/model-relationships-test.js b/tests/integration/validations/model-relationships-test.js index bbd81495..968534ba 100644 --- a/tests/integration/validations/model-relationships-test.js +++ b/tests/integration/validations/model-relationships-test.js @@ -3,7 +3,7 @@ import ArrayProxy from '@ember/array/proxy'; import EmberObject from '@ember/object'; import { isNone } from '@ember/utils'; import { A as emberArray } from '@ember/array'; -import DS from 'ember-data'; +import Model, { belongsTo, hasMany } from '@ember-data/model'; import setupObject from '../../helpers/setup-object'; import DefaultMessages from 'dummy/validators/messages'; import BelongsToValidator from 'ember-cp-validations/validators/belongs-to'; @@ -508,16 +508,22 @@ module('Integration | Validations | Model Relationships', function (hooks) { assert.true(user.get('validations.attrs.fullName.isValid')); }); - test('presence on empty DS.PromiseObject', function (assert) { + test('presence on empty belongsTo - sync', function (assert) { this.owner.register('validator:presence', PresenceValidator); + this.owner.register( + 'model:user', + Model.extend( + buildValidations({ + friend: validator('presence', true), + }), + { + friend: belongsTo('user', { async: false, inverse: null }), + } + ) + ); - let Validations = buildValidations({ - friend: validator('presence', true), - }); - - let user = setupObject(this, EmberObject.extend(Validations), { - friend: DS.PromiseObject.create(), - }); + const store = this.owner.lookup('service:store'); + const user = store.createRecord('user'); let { validations, model } = user.get('validations').validateSync(); @@ -533,16 +539,53 @@ module('Integration | Validations | Model Relationships', function (hooks) { assert.strictEqual(friend.get('message'), "This field can't be blank"); }); - test('presence on empty DS.PromiseArray', function (assert) { + test('presence on empty belongsTo - async', async function (assert) { this.owner.register('validator:presence', PresenceValidator); + this.owner.register( + 'model:user', + Model.extend( + buildValidations({ + friend: validator('presence', true), + }), + { + friend: belongsTo('user', { async: true, inverse: null }), + } + ) + ); - let Validations = buildValidations({ - friends: validator('presence', true), - }); + const store = this.owner.lookup('service:store'); + const user = store.createRecord('user'); - let user = setupObject(this, EmberObject.extend(Validations), { - friends: DS.PromiseArray.create(), - }); + let { validations, model } = await user.get('validations').validate(); + + assert.strictEqual(model, user, 'expected model to be the correct model'); + assert.deepEqual( + validations.get('content').getEach('attribute').sort(), + ['friend'].sort() + ); + + let friend = validations.get('content').findBy('attribute', 'friend'); + + assert.false(friend.get('isValid')); + assert.strictEqual(friend.get('message'), "This field can't be blank"); + }); + + test('presence on empty hasMany - sync', function (assert) { + this.owner.register('validator:presence', PresenceValidator); + this.owner.register( + 'model:user', + Model.extend( + buildValidations({ + friends: validator('presence', true), + }), + { + friends: hasMany('user', { async: false, inverse: null }), + } + ) + ); + + const store = this.owner.lookup('service:store'); + const user = store.createRecord('user'); let { validations, model } = user.get('validations').validateSync(); @@ -558,6 +601,37 @@ module('Integration | Validations | Model Relationships', function (hooks) { assert.strictEqual(friends.get('message'), "This field can't be blank"); }); + test('presence on empty hasMany - async', async function (assert) { + this.owner.register('validator:presence', PresenceValidator); + this.owner.register( + 'model:user', + Model.extend( + buildValidations({ + friends: validator('presence', true), + }), + { + friends: hasMany('user', { async: true, inverse: null }), + } + ) + ); + + const store = this.owner.lookup('service:store'); + const user = store.createRecord('user'); + + let { validations, model } = await user.get('validations').validate(); + + assert.strictEqual(model, user, 'expected model to be the correct model'); + assert.deepEqual( + validations.get('content').getEach('attribute').sort(), + ['friends'].sort() + ); + + let friends = validations.get('content').findBy('attribute', 'friends'); + + assert.false(friends.get('isValid')); + assert.strictEqual(friends.get('message'), "This field can't be blank"); + }); + test('debounce should work across nested HasMany relationships', function (assert) { this.owner.register('validator:presence', PresenceValidator); this.owner.register('validator:has-many', HasManyValidator);