Skip to content

Commit

Permalink
feat(resolve): Remove RXWAIT async policy in favour of allowing user …
Browse files Browse the repository at this point in the history
…defined async policy function (#366)

BREAKING CHANGE: RXWAIT async policy has been removed, but it never worked in the first place
  • Loading branch information
wawyed authored Sep 26, 2019
1 parent df263a9 commit 0ad87f6
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 35 deletions.
3 changes: 2 additions & 1 deletion src/resolve/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ export interface ResolvePolicy {
}

export type PolicyWhen = 'LAZY' | 'EAGER';
export type PolicyAsync = 'WAIT' | 'NOWAIT' | 'RXWAIT';
export type PolicyAsync = 'WAIT' | 'NOWAIT' | CustomAsyncPolicy;
export type CustomAsyncPolicy = <TResolveFnResult, TResolveValue>(data: TResolveFnResult) => Promise<TResolveValue>;

/** @internalapi */
export let resolvePolicies = {
Expand Down
26 changes: 6 additions & 20 deletions src/resolve/resolvable.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/** @publicapi @module resolve */ /** */
import { extend, equals, inArray, identity } from '../common/common';
import { extend, identity } from '../common/common';
import { services } from '../common/coreservices';
import { trace } from '../common/trace';
import { ResolvePolicy, ResolvableLiteral, resolvePolicies } from './interface';
import { ResolvePolicy, ResolvableLiteral, PolicyAsync } from './interface';

import { ResolveContext } from './resolveContext';
import { stringify } from '../common/strings';
Expand Down Expand Up @@ -117,26 +117,12 @@ export class Resolvable implements ResolvableLiteral {
// Invokes the resolve function passing the resolved dependencies as arguments
const invokeResolveFn = (resolvedDeps: any[]) => this.resolveFn.apply(null, resolvedDeps);

/**
* For RXWAIT policy:
*
* Given an observable returned from a resolve function:
* - enables .cache() mode (this allows multicast subscribers)
* - then calls toPromise() (this triggers subscribe() and thus fetches)
* - Waits for the promise, then return the cached observable (not the first emitted value).
*/
const waitForRx = (observable$: any) => {
const cached = observable$.cache(1);
return cached
.take(1)
.toPromise()
.then(() => cached);
};

// If the resolve policy is RXWAIT, wait for the observable to emit something. otherwise pass through.
const node: PathNode = resolveContext.findNode(this);
const state: StateObject = node && node.state;
const maybeWaitForRx = this.getPolicy(state).async === 'RXWAIT' ? waitForRx : identity;

const asyncPolicy: PolicyAsync = this.getPolicy(state).async;
const customAsyncPolicy = isFunction(asyncPolicy) ? asyncPolicy : identity;

// After the final value has been resolved, update the state of the Resolvable
const applyResolvedValue = (resolvedValue: any) => {
Expand All @@ -152,7 +138,7 @@ export class Resolvable implements ResolvableLiteral {
.when()
.then(getResolvableDependencies)
.then(invokeResolveFn)
.then(maybeWaitForRx)
.then(customAsyncPolicy)
.then(applyResolvedValue));
}

Expand Down
66 changes: 52 additions & 14 deletions test/resolveSpec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { ResolveContext, StateObject, PathNode, Resolvable, copy } from '../src/index';
import { tail } from '../src/common/common';
import { services } from '../src/common/coreservices';
import { tree2Array } from './_testUtils';
import { copy, CustomAsyncPolicy, PathNode, Resolvable, ResolveContext, StateObject } from '../src/index';
import { UIRouter } from '../src/router';

import { TestingPlugin } from './_testingPlugin';
import { StateRegistry } from '../src/state/stateRegistry';
import { StateService } from '../src/state/stateService';
import { TransitionService } from '../src/transition/transitionService';
import { StateRegistry } from '../src/state/stateRegistry';
import { tail } from '../src/common/common';

import { TestingPlugin } from './_testingPlugin';
import { tree2Array } from './_testUtils';

///////////////////////////////////////////////

Expand Down Expand Up @@ -426,6 +426,7 @@ describe('Resolvables system:', function() {
const ctx = new ResolveContext(path);

let result;

function checkCounts() {
expect(result).toBe('JJ2K');
expect(counts['_J']).toBe(1);
Expand Down Expand Up @@ -561,10 +562,11 @@ describe('Resolvables system:', function() {

describe('NOWAIT Resolve Policy', () => {
it('should allow a transition to complete before the resolve is settled', async done => {
let resolve,
resolvePromise = new Promise(_resolve => {
resolve = _resolve;
});
let resolve;

const resolvePromise = new Promise(_resolve => {
resolve = _resolve;
});

$registry.register({
name: 'nowait',
Expand Down Expand Up @@ -599,10 +601,11 @@ describe('Resolvables system:', function() {
});

it('should wait for WAIT resolves and not wait for NOWAIT resolves', async done => {
let promiseResolveFn,
resolvePromise = new Promise(resolve => {
promiseResolveFn = resolve;
});
let promiseResolveFn;

const resolvePromise = new Promise(resolve => {
promiseResolveFn = resolve;
});

$registry.register({
name: 'nowait',
Expand Down Expand Up @@ -635,4 +638,39 @@ describe('Resolvables system:', function() {
$state.go('nowait');
});
});

describe('custom Resolve Policy', () => {
let customResolvePolicy: CustomAsyncPolicy;

it('should wait for the promise to resolve before finishing the transition', async done => {
let resolve: (value: string) => void;

const resolvePromise: Promise<string> = new Promise(_resolve => {
resolve = _resolve;
});

customResolvePolicy = jasmine.createSpy('customResolvePolicy');

(customResolvePolicy as jasmine.Spy).and.callFake((data: { useMe: Promise<string> }) => {
return data.useMe;
});

resolve('myAwaitedValue');

$registry.register({
name: 'customPolicy',
resolve: {
customWait: () => ({ useMe: resolvePromise }),
},
resolvePolicy: { async: customResolvePolicy },
});

$transitions.onSuccess({}, trans => {
expect(customResolvePolicy).toHaveBeenCalledWith({ useMe: resolvePromise });
expect(trans.injector().get('customWait')).toBe('myAwaitedValue');
});

$state.go('customPolicy').then(done);
});
});
});

0 comments on commit 0ad87f6

Please sign in to comment.