Skip to content

Commit

Permalink
Fix waiter left behind when resource is canceled before promise resolves
Browse files Browse the repository at this point in the history
  • Loading branch information
josemarluedke committed Sep 29, 2023
1 parent f3de5dd commit 47dac13
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 9 deletions.
19 changes: 13 additions & 6 deletions packages/glimmer-apollo/src/-private/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ export interface QueryOptions<TData, TVariables extends OperationVariables>
export type QueryPositionalArgs<
TData,
TVariables extends OperationVariables = OperationVariables
> = [DocumentNode, QueryOptions<TData, TVariables>?];
> = [DocumentNode, QueryOptions<TData, TVariables>?];

Check failure on line 34 in packages/glimmer-apollo/src/-private/query.ts

View workflow job for this annotation

GitHub Actions / Linting

Delete `··`

export class QueryResource<
TData,
TVariables extends OperationVariables = OperationVariables
> extends ObservableResource<
> extends ObservableResource<

Check failure on line 39 in packages/glimmer-apollo/src/-private/query.ts

View workflow job for this annotation

GitHub Actions / Linting

Delete `··`
TData,
TVariables,
TemplateArgs<QueryPositionalArgs<TData, TVariables>>
> {
> {

Check failure on line 43 in packages/glimmer-apollo/src/-private/query.ts

View workflow job for this annotation

GitHub Actions / Linting

Delete `··`
@tracked loading = true;
@tracked error?: ApolloError;
@tracked data: TData | undefined;
Expand All @@ -50,6 +50,8 @@ export class QueryResource<
#subscription?: ObservableSubscription;
#previousPositionalArgs: typeof this.args.positional | undefined;

#firstPromiseReject: Function | undefined;

/** @internal */
async setup(): Promise<void> {
this.#previousPositionalArgs = this.args.positional;
Expand All @@ -64,6 +66,7 @@ export class QueryResource<
}

let [promise, firstResolve, firstReject] = createPromise(); // eslint-disable-line prefer-const
this.#firstPromiseReject = firstReject;
this.promise = promise;
const observable = client.watchQuery({
query,
Expand All @@ -82,9 +85,9 @@ export class QueryResource<
},
(error) => {
this.#onError(error);
if (firstReject) {
firstReject();
firstReject = undefined;
if (this.#firstPromiseReject) {
this.#firstPromiseReject();
this.#firstPromiseReject = undefined;
}
}
);
Expand Down Expand Up @@ -112,6 +115,10 @@ export class QueryResource<
if (this.#subscription) {
this.#subscription.unsubscribe();
}
if (this.#firstPromiseReject) {
this.#firstPromiseReject();
this.#firstPromiseReject = undefined;
}
}

settled(): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion packages/test-app/app/components/playground/experiment.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<h2>
<h2 data-test-id="experiment">
User Info
</h2>

Expand Down
1 change: 1 addition & 0 deletions packages/test-app/app/components/playground/experiment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default class PlaygroundExperiment extends Component {
userInfo = useQuery(this, () => [
USER_INFO,
{
variables: { id: '1-with-delay' },
errorPolicy: 'all',
notifyOnNetworkStatusChange: true
}
Expand Down
2 changes: 1 addition & 1 deletion packages/test-app/app/components/playground/index.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<button type="button" {{on "click" this.toggle}}>
<button type="button" {{on "click" this.toggle}} dates-test-id="toggle">
Toggle Experiment
</button>

Expand Down
2 changes: 1 addition & 1 deletion packages/test-app/app/components/playground/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';

export default class Playground extends Component {
@tracked isExperimenting = true;
@tracked isExperimenting = false;

toggle = (): void => {
this.isExperimenting = !this.isExperimenting;
Expand Down
10 changes: 10 additions & 0 deletions packages/test-app/app/mocks/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ export const handlers = [
}
})
);
} else if (user && req.variables.id.includes('with-delay')) {
return res(
ctx.delay(300),
ctx.data({
user: {
__typename: 'User',
...user
}
})
);
} else if (user) {
return res(
ctx.data({
Expand Down
18 changes: 18 additions & 0 deletions packages/test-app/tests/integration/components/playground-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { hbs } from 'ember-cli-htmlbars';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { click, render, waitFor } from '@ember/test-helpers';

module('Integration | Components | Playground', function(hooks) {

Check failure on line 6 in packages/test-app/tests/integration/components/playground-test.ts

View workflow job for this annotation

GitHub Actions / Linting

Insert `·`
setupRenderingTest(hooks);

test('no waiters should be left behind when resource is teardown before resolving', async function(this, assert) {

Check failure on line 9 in packages/test-app/tests/integration/components/playground-test.ts

View workflow job for this annotation

GitHub Actions / Linting

Insert `·`
await render(hbs`<Playground />`);

click('[dates-test-id="toggle"]');
await waitFor('[data-test-id="experiment"]', { timeout: 100 });

await click('[dates-test-id="toggle"]');
assert.ok(true);
});
});

0 comments on commit 47dac13

Please sign in to comment.