Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ember-data feature detection #737

Draft
wants to merge 3 commits into
base: update-ember-cli-to-4-12
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
27 changes: 15 additions & 12 deletions addon/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
}
Expand Down
106 changes: 90 additions & 16 deletions tests/integration/validations/model-relationships-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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();

Expand All @@ -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();

Expand All @@ -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);
Expand Down
Loading