diff --git a/addon/-private/async-arrow-runtime.js b/addon/-private/async-arrow-runtime.js index 78cb767cd..e9acb4fbb 100644 --- a/addon/-private/async-arrow-runtime.js +++ b/addon/-private/async-arrow-runtime.js @@ -16,6 +16,13 @@ export function buildTask(contextFn, options, taskName, bufferPolicyName) { const result = contextFn(); + if (optionsWithBufferPolicy && optionsWithBufferPolicy.waitFor) { + result.generator = optionsWithBufferPolicy.waitFor(result.generator); + + optionsWithBufferPolicy = Object.assign({}, optionsWithBufferPolicy); + delete optionsWithBufferPolicy.waitFor; + } + const taskFactory = new TaskFactory( taskName || '', result.generator, diff --git a/addon/index.d.ts b/addon/index.d.ts index 567a189c9..ea8a2fd6b 100644 --- a/addon/index.d.ts +++ b/addon/index.d.ts @@ -796,6 +796,16 @@ type OptionTypeFor = F extends (...args: infer Args) => T type TaskOptions = OptionsFor>; type TaskGroupOptions = OptionsFor>; +type AsyncArrowFunctionTaskOptions< + HostObject, + T, + Args extends any[] +> = TaskOptions & { + waitFor?: ( + fn: AsyncArrowTaskFunction + ) => AsyncArrowTaskFunction; +}; + type MethodOrPropertyDecoratorWithParams = MethodDecorator & PropertyDecorator & @@ -919,7 +929,7 @@ export function task< export function task< HostObject, - O extends TaskOptions, + O extends AsyncArrowFunctionTaskOptions, T extends AsyncArrowTaskFunction >( hostObject: HostObject, @@ -929,7 +939,7 @@ export function task< export function task< HostObject, - O extends TaskOptions, + O extends AsyncArrowFunctionTaskOptions, T extends AsyncArrowTaskFunction >(baseOptions: O, asyncArrowTaskFn: T): TaskForAsyncTaskFunction; @@ -981,7 +991,7 @@ export function dropTask< >(asyncArrowTaskFn: T): TaskForAsyncTaskFunction; export function dropTask< HostObject, - O extends TaskOptions, + O extends AsyncArrowFunctionTaskOptions, T extends AsyncArrowTaskFunction >(baseOptions: O, asyncArrowTaskFn: T): TaskForAsyncTaskFunction; @@ -1030,7 +1040,7 @@ export function enqueueTask< export function enqueueTask< HostObject, - O extends TaskOptions, + O extends AsyncArrowFunctionTaskOptions, T extends AsyncArrowTaskFunction >(baseOptions: O, asyncArrowTaskFn: T): TaskForAsyncTaskFunction; @@ -1079,7 +1089,7 @@ export function keepLatestTask< export function keepLatestTask< HostObject, - O extends TaskOptions, + O extends AsyncArrowFunctionTaskOptions, T extends AsyncArrowTaskFunction >(baseOptions: O, asyncArrowTaskFn: T): TaskForAsyncTaskFunction; @@ -1128,7 +1138,7 @@ export function restartableTask< export function restartableTask< HostObject, - O extends TaskOptions, + O extends AsyncArrowFunctionTaskOptions, T extends AsyncArrowTaskFunction >(baseOptions: O, asyncArrowTaskFn: T): TaskForAsyncTaskFunction; diff --git a/tests/integration/async-arrow-task-test.js b/tests/integration/async-arrow-task-test.js index dc33f2b63..16b4d1da2 100644 --- a/tests/integration/async-arrow-task-test.js +++ b/tests/integration/async-arrow-task-test.js @@ -2,7 +2,14 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; // eslint-disable-next-line ember/no-computed-properties-in-native-classes import { computed, set } from '@ember/object'; -import { click, render, settled } from '@ember/test-helpers'; +import { + click, + getSettledState, + render, + settled, + waitUntil, +} from '@ember/test-helpers'; +import { waitFor } from '@ember/test-waiters'; import { hbs } from 'ember-cli-htmlbars'; import { task, @@ -142,6 +149,36 @@ module('Integration | async-arrow-task', function (hooks) { await finishTest(assert); }); + test('waitFor option', async function (assert) { + assert.expect(9); + + let { promise, resolve } = defer(); + + this.owner.register( + 'component:test-async-arrow-task', + class extends TestComponent { + myTask = task(this, { waitFor }, async (arg) => { + set(this, 'resolved', await promise); + assert.strictEqual(this.myTask.name, 'myTask'); + return arg; + }); + } + ); + + await render(hbs``); + click('button#start'); + await waitUntil(() => this.element.textContent.includes('Running!')); + + assert.true(getSettledState().hasPendingWaiters); + + resolve('Wow!'); + await settled(); + + assert.false(getSettledState().hasPendingWaiters); + + await finishTest(assert); + }); + test('dropTask and other shorthand tasks (with `this` arg)', async function (assert) { assert.expect(13); diff --git a/tests/types/ember-concurrency-test.ts b/tests/types/ember-concurrency-test.ts index 3c09fa8f0..9a96c3939 100644 --- a/tests/types/ember-concurrency-test.ts +++ b/tests/types/ember-concurrency-test.ts @@ -58,6 +58,7 @@ import { } from 'ember-concurrency'; import { expectTypeOf as expect } from 'expect-type'; import { taskFor } from 'ember-concurrency-ts'; +import { waitFor } from '@ember/test-waiters'; declare type TestCallback = () => void | Promise; declare function module(description: string, callback: TestCallback): void; @@ -3128,6 +3129,7 @@ module('integration tests', () => { debug = task(this, { debug: true }, async () => {}); onState = task(this, { onState: () => {} }, async () => {}); onStateNull = task(this, { onState: null }, async () => {}); + waitFor = task({ waitFor }, async () => {}); // Note: these options work even when strictFunctionTypes is enabled, but // turning it on in this repo breaks other things in addon/index.d.ts @@ -3237,6 +3239,7 @@ module('integration tests', () => { debug = task({ debug: true }, async () => {}); onState = task({ onState: () => {} }, async () => {}); onStateNull = task({ onState: null }, async () => {}); + waitFor = task({ waitFor }, async () => {}); // Note: these options work even when strictFunctionTypes is enabled, but // turning it on in this repo breaks other things in addon/index.d.ts @@ -3409,6 +3412,7 @@ module('integration tests', () => { debug = task({ debug: true }, async () => {}); onState = task({ onState: () => {} }, async () => {}); onStateNull = task({ onState: null }, async () => {}); + waitFor = task({ waitFor }, async () => {}); // Note: these options work even when strictFunctionTypes is enabled, but // turning it on in this repo breaks other things in addon/index.d.ts