write tests for AsyncMappedList
This commit is contained in:
parent
1fc1d2c79b
commit
81f06f565e
3 changed files with 76 additions and 43 deletions
|
@ -16,67 +16,46 @@ limitations under the License.
|
||||||
|
|
||||||
export class ListObserver {
|
export class ListObserver {
|
||||||
constructor() {
|
constructor() {
|
||||||
this._queuesPerType = new Map();
|
this._queue = [];
|
||||||
|
this._backlog = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
_nextEvent(type) {
|
next() {
|
||||||
let queue = this._queuesPerType.get(type);
|
if (this._backlog.length) {
|
||||||
if (!queue) {
|
return Promise.resolve(this._backlog.shift());
|
||||||
queue = [];
|
} else {
|
||||||
this._queuesPerType.set(type, queue);
|
|
||||||
}
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
queue.push(resolve);
|
this._queue.push(resolve);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
nextAdd() {
|
|
||||||
return this._nextEvent("add");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nextUpdate() {
|
_fullfillNext(value) {
|
||||||
return this._nextEvent("update");
|
if (this._queue.length) {
|
||||||
|
const resolve = this._queue.shift();
|
||||||
|
resolve(value);
|
||||||
|
} else {
|
||||||
|
this._backlog.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
nextRemove() {
|
|
||||||
return this._nextEvent("remove");
|
|
||||||
}
|
|
||||||
|
|
||||||
nextMove() {
|
|
||||||
return this._nextEvent("move");
|
|
||||||
}
|
|
||||||
|
|
||||||
nextReset() {
|
|
||||||
return this._nextEvent("reset");
|
|
||||||
}
|
|
||||||
|
|
||||||
_popQueue(type) {
|
|
||||||
const queue = this._queuesPerType.get(type);
|
|
||||||
return queue?.unshift();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onReset() {
|
onReset() {
|
||||||
const resolve = this._popQueue("reset");
|
this._fullfillNext({type: "reset"});
|
||||||
resolve && resolve();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onAdd(index, value) {
|
onAdd(index, value) {
|
||||||
const resolve = this._popQueue("add");
|
this._fullfillNext({type: "add", index, value});
|
||||||
resolve && resolve({index, value});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdate(index, value, params) {
|
onUpdate(index, value, params) {
|
||||||
const resolve = this._popQueue("update");
|
this._fullfillNext({type: "update", index, value, params});
|
||||||
resolve && resolve({index, value, params});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemove(index, value) {
|
onRemove(index, value) {
|
||||||
const resolve = this._popQueue("remove");
|
this._fullfillNext({type: "remove", index, value});
|
||||||
resolve && resolve({index, value});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMove(fromIdx, toIdx, value) {
|
onMove(fromIdx, toIdx, value) {
|
||||||
const resolve = this._popQueue("move");
|
this._fullfillNext({type: "move", fromIdx, toIdx, value});
|
||||||
resolve && resolve({fromIdx, toIdx, value});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,8 +143,55 @@ class ResetEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import {ObservableArray} from "./ObservableArray.js";
|
||||||
|
import {ListObserver} from "../../mocks/ListObserver.js";
|
||||||
|
|
||||||
export function tests() {
|
export function tests() {
|
||||||
return {
|
return {
|
||||||
|
"events are emitted in order": async assert => {
|
||||||
|
const double = n => n * n;
|
||||||
|
const source = new ObservableArray();
|
||||||
|
const mapper = new AsyncMappedList(source, async n => {
|
||||||
|
await new Promise(r => setTimeout(r, n));
|
||||||
|
return {n: double(n)};
|
||||||
|
}, (o, params, n) => {
|
||||||
|
o.n = double(n);
|
||||||
|
});
|
||||||
|
const observer = new ListObserver();
|
||||||
|
mapper.subscribe(observer);
|
||||||
|
source.append(2); // will sleep this amount, so second append would take less time
|
||||||
|
source.append(1);
|
||||||
|
source.update(0, 7, "lucky seven")
|
||||||
|
source.remove(0);
|
||||||
|
{
|
||||||
|
const {type, index, value} = await observer.next();
|
||||||
|
assert.equal(mapper.length, 1);
|
||||||
|
assert.equal(type, "add");
|
||||||
|
assert.equal(index, 0);
|
||||||
|
assert.equal(value.n, 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const {type, index, value} = await observer.next();
|
||||||
|
assert.equal(mapper.length, 2);
|
||||||
|
assert.equal(type, "add");
|
||||||
|
assert.equal(index, 1);
|
||||||
|
assert.equal(value.n, 1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const {type, index, value, params} = await observer.next();
|
||||||
|
assert.equal(mapper.length, 2);
|
||||||
|
assert.equal(type, "update");
|
||||||
|
assert.equal(index, 0);
|
||||||
|
assert.equal(value.n, 49);
|
||||||
|
assert.equal(params, "lucky seven");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const {type, index, value} = await observer.next();
|
||||||
|
assert.equal(mapper.length, 1);
|
||||||
|
assert.equal(type, "remove");
|
||||||
|
assert.equal(index, 0);
|
||||||
|
assert.equal(value.n, 49);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,13 @@ export class ObservableArray extends BaseObservableList {
|
||||||
this.emitAdd(idx, item);
|
this.emitAdd(idx, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update(idx, item, params = null) {
|
||||||
|
if (idx < this._items.length) {
|
||||||
|
this._items[idx] = item;
|
||||||
|
this.emitUpdate(idx, item, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get array() {
|
get array() {
|
||||||
return this._items;
|
return this._items;
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue