Skip to content

Commit f04e04a

Browse files
authored
Fix updating fragment arrays multiple times in the same runloop (#487)
* run CI in production environment * upgrade ember-try Fixes the following error: Error: Cannot copy '../../../browserslist/cli.js' to a subdirectory of itself, '../../../browserslist/cli.js'. at /home/runner/work/ember-data-model-fragments/ember-data-model-fragments/node_modules/ember-try/node_modules/fs-extra/lib/copy/copy.js:210:21 at FSReqCallback.oncomplete (fs.js:180:23) ember-cli/ember-try#967 * upgrade to node.js 18 * fix store.find deprecation * replace assert.throws with expectAssertion * fix updating fragment array multiple times * revert to node 14 and use `yarn --ignore-engines`
1 parent 2e3fc50 commit f04e04a

File tree

11 files changed

+98
-33
lines changed

11 files changed

+98
-33
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ jobs:
7777
${{ runner.os }}-${{ matrix.node-version }}-
7878
7979
- name: Install Dependencies
80-
run: yarn install --frozen-lockfile
80+
run: yarn install --frozen-lockfile --ignore-engines
8181
if: |
8282
steps.cache-dependencies.outputs.cache-hit != 'true'
8383
@@ -121,7 +121,7 @@ jobs:
121121
${{ runner.os }}-${{ matrix.node-version }}-
122122
123123
- name: Install Dependencies
124-
run: yarn install --frozen-lockfile
124+
run: yarn install --frozen-lockfile --ignore-engines
125125
if: |
126126
steps.cache-dependencies.outputs.cache-hit != 'true'
127127
@@ -163,7 +163,7 @@ jobs:
163163
${{ runner.os }}-${{ matrix.node-version }}-
164164
165165
- name: Install Dependencies
166-
run: yarn install --no-lockfile --non-interactive
166+
run: yarn install --no-lockfile --non-interactive --ignore-engines
167167

168168
- name: Test
169169
run: yarn test:ember --launch ${{ matrix.browser }}
@@ -217,11 +217,16 @@ jobs:
217217
${{ runner.os }}-${{ matrix.node-version }}-
218218
219219
- name: Install Dependencies
220-
run: yarn install --frozen-lockfile
220+
run: yarn install --frozen-lockfile --ignore-engines
221221
if: |
222222
steps.cache-dependencies.outputs.cache-hit != 'true'
223223
224224
- name: Test
225225
env:
226226
EMBER_TRY_SCENARIO: ${{ matrix.ember-try-scenario }}
227227
run: node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO
228+
229+
- name: Test (Prod)
230+
env:
231+
EMBER_TRY_SCENARIO: ${{ matrix.ember-try-scenario }}
232+
run: node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO --- ember test --environment=production

addon/array/stateful.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ const StatefulArray = EmberObject.extend(MutableArray, Copyable, {
115115
// array is unchanged
116116
return;
117117
}
118+
if (this._isDirty) {
119+
this.retrieveLatest();
120+
}
118121
const data = this.currentState.slice();
119122
data.splice(
120123
start,

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"ember-source": "~4.6.0",
6868
"ember-source-channel-url": "^3.0.0",
6969
"ember-template-lint": "^5.3.1",
70-
"ember-try": "^2.0.0",
70+
"ember-try": "^3.0.0",
7171
"eslint": "^7.32.0",
7272
"eslint-config-prettier": "^8.6.0",
7373
"eslint-plugin-ember": "^11.4.3",

tests/helpers/assertion.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { getDebugFunction, setDebugFunction } from '@ember/debug';
2+
import { DEBUG } from '@glimmer/env';
3+
4+
/**
5+
* Asserts that `Ember.assert` is called with a falsy condition
6+
* @param func function which calls `Ember.assert`
7+
* @param expectedMessage the expected assertion text to compare with the first argument to `Ember.assert`
8+
*/
9+
function expectAssertion(func, expectedMessage) {
10+
if (!DEBUG) {
11+
this.ok(true, 'Assertions disabled in production builds');
12+
return;
13+
}
14+
const originalAssertFunc = getDebugFunction('assert');
15+
try {
16+
let called = false;
17+
let failed = false;
18+
let actualMessage;
19+
setDebugFunction('assert', function assert(desc, test) {
20+
called = true;
21+
if (!test) {
22+
failed = true;
23+
actualMessage = desc;
24+
}
25+
});
26+
func();
27+
this.true(called, `Expected Ember.assert to be called`);
28+
this.true(failed, `Expected Ember.assert to fail its test`);
29+
this.strictEqual(
30+
actualMessage,
31+
expectedMessage,
32+
'Expected Ember.assert message to match'
33+
);
34+
} finally {
35+
// restore original assert function
36+
setDebugFunction('assert', originalAssertFunc);
37+
}
38+
}
39+
40+
export function setup(assert) {
41+
assert.expectAssertion = expectAssertion;
42+
}

tests/test-helper.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import Application from 'dummy/app';
22
import config from 'dummy/config/environment';
33
import * as QUnit from 'qunit';
44
import { setApplication } from '@ember/test-helpers';
5-
import { setup } from 'qunit-dom';
5+
import { setup as setupQunitDom } from 'qunit-dom';
6+
import { setup as setupCustomAssertions } from './helpers/assertion';
67
import { start } from 'ember-qunit';
78

89
setApplication(Application.create(config.APP));
910

10-
setup(QUnit.assert);
11+
setupQunitDom(QUnit.assert);
12+
setupCustomAssertions(QUnit.assert);
1113

1214
start();

tests/unit/fragment_array_property_test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,11 @@ module('unit - `MF.fragmentArray` property', function (hooks) {
195195
const person = await store.findRecord('person', 1);
196196
const addresses = person.addresses;
197197

198-
assert.throws(() => {
198+
assert.expectAssertion(() => {
199199
const otherPerson = store.createRecord('person');
200200

201201
addresses.addFragment(otherPerson);
202-
}, 'error is thrown when adding a DS.Model instance');
202+
}, "You can only add 'address' fragments or object literals to this property");
203203
});
204204

205205
test('adding fragments from other records throws an error', async function (assert) {
@@ -212,9 +212,9 @@ module('unit - `MF.fragmentArray` property', function (hooks) {
212212
]);
213213
const address = people[0].addresses.firstObject;
214214

215-
assert.throws(() => {
215+
assert.expectAssertion(() => {
216216
people[1].addresses.addFragment(address);
217-
}, 'error is thrown when adding a fragment from another record');
217+
}, 'Fragments can only belong to one owner, try copying instead');
218218
});
219219

220220
test('setting to an array of fragments is allowed', async function (assert) {
@@ -422,9 +422,9 @@ module('unit - `MF.fragmentArray` property', function (hooks) {
422422
pushPerson(1);
423423

424424
const person = await store.findRecord('person', 1);
425-
assert.throws(() => {
425+
assert.expectAssertion(() => {
426426
person.set('addresses', ['address']);
427-
}, 'error is thrown when setting to an array of non-fragments');
427+
}, "You can only add 'address' fragments or object literals to this property");
428428
});
429429

430430
test('fragments can have default values', function (assert) {

tests/unit/fragment_owner_property_test.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,9 @@ module('unit - `MF.fragmentOwner` property', function (hooks) {
5252

5353
const invalid = store.createRecord('invalidModel');
5454

55-
assert.throws(
56-
() => {
57-
invalid.owner;
58-
},
59-
/Fragment owner properties can only be used on fragments/,
60-
'getting fragment owner on non-fragment throws an error'
61-
);
55+
assert.expectAssertion(() => {
56+
invalid.owner;
57+
}, 'Fragment owner properties can only be used on fragments.');
6258
});
6359

6460
test("attempting to change a fragment's owner record throws an error", async function (assert) {

tests/unit/fragment_property_test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ module('unit - `MF.fragment` property', function (hooks) {
111111
});
112112

113113
const person = await store.findRecord('person', 1);
114-
assert.throws(() => {
114+
assert.expectAssertion(() => {
115115
person.set('name', store.createRecord('person'));
116-
}, 'error is thrown when setting non-fragment');
116+
}, 'You must pass a fragment or null to set a fragment');
117117
});
118118

119119
test('setting fragments from other records throws an error', async function (assert) {
@@ -142,9 +142,9 @@ module('unit - `MF.fragment` property', function (hooks) {
142142
store.findRecord('person', 1),
143143
store.findRecord('person', 2),
144144
]);
145-
assert.throws(() => {
145+
assert.expectAssertion(() => {
146146
people[1].set('name', people[0].name);
147-
}, 'error is thrown when setting to a fragment of another record');
147+
}, 'Fragments can only belong to one owner, try copying instead');
148148
});
149149

150150
test('null values are allowed', async function (assert) {

tests/unit/polymorphic_test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ module('unit - Polymorphism', function (hooks) {
9494
},
9595
});
9696

97-
const record = await store.find('zoo', 1);
97+
const record = await store.findRecord('zoo', 1);
9898
const animals = record.animals;
9999

100100
const newLion = animals.createFragment({
@@ -138,7 +138,7 @@ module('unit - Polymorphism', function (hooks) {
138138
},
139139
});
140140

141-
const component = await store.find('component', 1);
141+
const component = await store.findRecord('component', 1);
142142
const textOptions = component.optionsHistory.createFragment({
143143
fontFamily: 'Verdana',
144144
fontSize: 12,

tests/unit/store_test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ module('unit - `DS.Store`', function (hooks) {
2929
});
3030

3131
test('attempting to create a fragment type that does not inherit from `MF.Fragment` throws an error', function (assert) {
32-
assert.throws(() => {
32+
assert.expectAssertion(() => {
3333
store.createFragment('person');
34-
}, 'an error is thrown when given a bad type');
34+
}, "The 'person' model must be a subclass of MF.Fragment");
3535
});
3636

3737
test('the store has an `isFragment` method', function (assert) {

0 commit comments

Comments
 (0)