From 3541f8abb922fa9eb5094edbe32e63ea9cfc008c Mon Sep 17 00:00:00 2001 From: Matt Kobs Date: Wed, 2 Jun 2021 08:50:14 -0500 Subject: [PATCH 1/2] Added failing test case for tracking cache updates in a Controller --- tests/acceptance/watch-query-test.js | 25 ++++++++++++++++++- tests/dummy/app/controllers/movie.js | 9 +++++++ tests/dummy/app/gql/queries/movie.graphql | 7 ++++++ .../app/instance-initializers/mock-graphql.js | 4 +++ tests/dummy/app/schema.graphql | 9 +++++++ tests/dummy/app/templates/movie.hbs | 8 ++++++ 6 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 tests/dummy/app/controllers/movie.js diff --git a/tests/acceptance/watch-query-test.js b/tests/acceptance/watch-query-test.js index 806f8ee8..e3481dc5 100644 --- a/tests/acceptance/watch-query-test.js +++ b/tests/acceptance/watch-query-test.js @@ -13,6 +13,24 @@ module('Acceptance | watch query', function (hooks) { posterPath: '/dM2w364MScsjFf8pfMbaWUcWrR.jpg', overview: 'lorem', releaseDate: '1994-10-14', + reviews: { + edges: [], + __typename: 'ReviewsConnection', + }, + __typename: 'Movie', + }; + + const mockReviews = { + edges: [ + { + node: { + stars: 5, + __typename: 'Review', + }, + __typename: 'ReviewEdge', + }, + ], + __typename: 'ReviewsConnection', }; test('data should be updated when executing a mutation', async function (assert) { @@ -64,7 +82,10 @@ module('Acceptance | watch query', function (hooks) { return new Promise((resolve) => { setTimeout(() => { resolve( - Object.assign({}, mockMovie, { title: 'The Godfather' }) + Object.assign({}, mockMovie, { + title: 'The Godfather', + reviews: mockReviews, + }) ); }, 200); }); @@ -81,11 +102,13 @@ module('Acceptance | watch query', function (hooks) { assert.equal(currentURL(), '/movie/680'); assert.dom('.movie-title').hasText('Pulp Fiction'); + assert.dom('.movie-reviews').hasText('No reviews'); isRefetch = true; await click('.refetch-data-using-observable'); assert.dom('.movie-title').hasText('The Godfather'); + assert.dom('.movie-reviews').hasText('5 stars'); }); test('refetch using reoute refresh should update template', async function (assert) { diff --git a/tests/dummy/app/controllers/movie.js b/tests/dummy/app/controllers/movie.js new file mode 100644 index 00000000..0c4ca036 --- /dev/null +++ b/tests/dummy/app/controllers/movie.js @@ -0,0 +1,9 @@ +import Controller from '@ember/controller'; + +export default class MovieController extends Controller { + get reviews() { + return this.model.movie.reviews.edges.map((edge) => { + return edge.node; + }); + } +} diff --git a/tests/dummy/app/gql/queries/movie.graphql b/tests/dummy/app/gql/queries/movie.graphql index e058c68d..05840f8c 100644 --- a/tests/dummy/app/gql/queries/movie.graphql +++ b/tests/dummy/app/gql/queries/movie.graphql @@ -6,5 +6,12 @@ query GetMovie($id: ID!) { voteAverage posterPath releaseDate + reviews { + edges { + node { + stars + } + } + } } } diff --git a/tests/dummy/app/instance-initializers/mock-graphql.js b/tests/dummy/app/instance-initializers/mock-graphql.js index 3c04af12..5e664f88 100644 --- a/tests/dummy/app/instance-initializers/mock-graphql.js +++ b/tests/dummy/app/instance-initializers/mock-graphql.js @@ -115,6 +115,10 @@ function startPretender() { Date() { return '2019-09-28'; }, + + Int() { + return 5; + }, }; let schema = makeExecutableSchema({ typeDefs: schemaString, resolvers }); diff --git a/tests/dummy/app/schema.graphql b/tests/dummy/app/schema.graphql index 3b20a32d..a2454185 100644 --- a/tests/dummy/app/schema.graphql +++ b/tests/dummy/app/schema.graphql @@ -24,6 +24,7 @@ type Movie { voteAverage: Float posterPath: String releaseDate: Date + reviews: ReviewsConnection! } # Represents a review for a movie @@ -35,6 +36,14 @@ type Review { commentary: String } +type ReviewEdge { + node: Review! +} + +type ReviewsConnection { + edges: [ReviewEdge]! +} + # The input object sent when someone is creating a new review input ReviewInput { # 0-5 stars diff --git a/tests/dummy/app/templates/movie.hbs b/tests/dummy/app/templates/movie.hbs index 72399afe..bcac8b0a 100644 --- a/tests/dummy/app/templates/movie.hbs +++ b/tests/dummy/app/templates/movie.hbs @@ -38,3 +38,11 @@ + +
+ {{#each this.reviews as |review|}} +

{{review.stars}} stars

+ {{else}} +

No reviews

+ {{/each}} +
From 9a5a5843097a9413ac5b6e7bff79d9d72f82449a Mon Sep 17 00:00:00 2001 From: Matt Kobs Date: Wed, 2 Jun 2021 09:01:02 -0500 Subject: [PATCH 2/2] Added lightweight tracking support to returned data object --- addon/services/apollo.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/addon/services/apollo.js b/addon/services/apollo.js index d47237c0..7eaf69f3 100644 --- a/addon/services/apollo.js +++ b/addon/services/apollo.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { get, set, setProperties } from '@ember/object'; +import { get, set, setProperties, defineProperty } from '@ember/object'; import { sendEvent } from '@ember/object/events'; import RSVP from 'rsvp'; import Service from '@ember/service'; @@ -16,6 +16,7 @@ import { isNone, isPresent } from '@ember/utils'; import { run } from '@ember/runloop'; import { QueryManager } from '../index'; import { waitForPromise } from '@ember/test-waiters'; +import { tracked } from '@glimmer/tracking'; const apolloObservableWeakMap = new WeakMap(); const apolloUnsubscribeWeakMap = new WeakMap(); @@ -46,6 +47,20 @@ class EmberApolloSubscription { } } +class TrackedObject { + constructor() { + defineProperty(this, 'setUnknownProperty', { + configurable: false, + enumerable: false, + value: function (key, value) { + defineProperty(this, key, tracked()); + this[key] = value; + }, + writable: false, + }); + } +} + function extractNewData(resultKey, { data, loading }) { if (loading && isNone(data)) { // This happens when the cache has no data and the data is still loading @@ -75,7 +90,8 @@ function newDataFunc(observable, resultKey, resolve, unsubscribeFn = null) { if (isArray(dataToSend)) { obj = A([...dataToSend]); } else { - obj = { ...dataToSend }; + obj = new TrackedObject(); + setProperties(obj, dataToSend); } if (!apolloObservableWeakMap.has(obj)) {