diff --git a/src/components/ObsDetails/DQAContainer.js b/src/components/ObsDetails/DQAContainer.js index 357f2c041..680296643 100644 --- a/src/components/ObsDetails/DQAContainer.js +++ b/src/components/ObsDetails/DQAContainer.js @@ -18,17 +18,20 @@ import { compact, groupBy } from "lodash"; import { useCallback, useEffect, useState } from "react"; import * as React from "react"; import Observation from "realmModels/Observation"; +import { log } from "sharedHelpers/logger"; import { useAuthenticatedMutation, + useAuthenticatedQuery, useLocalObservation } from "sharedHooks"; import useRemoteObservation from "sharedHooks/useRemoteObservation"; +const logger = log.extend( "DQAContainer" ); + const DQAContainer = ( ): React.Node => { const { isInternetReachable: isOnline } = useNetInfo( ); const { params } = useRoute( ); const { observationUUID } = params; - const [qualityMetrics, setQualityMetrics] = useState( undefined ); const [loadingAgree, setLoadingAgree] = useState( false ); const [loadingDisagree, setLoadingDisagree] = useState( false ); const [loadingMetric, setLoadingMetric] = useState( "none" ); @@ -42,8 +45,9 @@ const DQAContainer = ( ): React.Node => { refetchRemoteObservation, isRefetching } = useRemoteObservation( observationUUID, fetchRemoteObservationEnabled ); - const observation - = localObservation || Observation.mapApiToRealm( remoteObservation ); + const observation = remoteObservation + ? Observation.mapApiToRealm( remoteObservation ) + : localObservation; const fetchMetricsParams = { id: observationUUID, @@ -70,21 +74,12 @@ const DQAContainer = ( ): React.Node => { } }; - // destructured mutate to pass into useEffect to prevent infinite - // rerender and disabling eslint useEffect dependency rule - const { mutate } = useAuthenticatedMutation( - ( p, o ) => fetchQualityMetrics( p, o ), - { - onSuccess: response => { - setNotLoading(); - setQualityMetrics( response ); - }, - onError: () => { - if ( !isOnline ) { - setHideOfflineSheet( false ); - } - } - } + const { + data: qualityMetrics, + refetch: refetchQualityMetrics + } = useAuthenticatedQuery( + ["fetchQualityMetrics", observationUUID], + optsWithAuth => fetchQualityMetrics( fetchMetricsParams, optsWithAuth ) ); const combinedQualityMetrics = { @@ -92,14 +87,6 @@ const DQAContainer = ( ): React.Node => { ...groupBy( observation?.votes, "vote_scope" ) }; - useEffect( ( ) => { - mutate( { - id: params.observationUUID, - fields: "metric,agree,user_id", - ttl: -1 - } ); - }, [mutate, params] ); - /** * After a success mutation of the needs_id vote we start the refetching of the remote * observation to update the metric status of the observation. So we need to wait until @@ -139,11 +126,13 @@ const DQAContainer = ( ): React.Node => { const createQualityMetricMutation = useAuthenticatedMutation( ( qualityMetricParams, optsWithAuth ) => setQualityMetric( qualityMetricParams, optsWithAuth ), { - onSuccess: () => { - // fetch updated quality metrics with updated votes - mutate( fetchMetricsParams ); + onSuccess: async ( ) => { + await refetchQualityMetrics( ); + await refetchRemoteObservation( ); + setNotLoading( ); }, - onError: () => { + onError: error => { + logger.error( "createQualityMetricMutation failure", error ); setHideErrorSheet( false ); } } @@ -176,14 +165,16 @@ const DQAContainer = ( ): React.Node => { faveMutation.mutate( faveParams ); }; - const createRemoveQualityMetricMutation = useAuthenticatedMutation( - ( p, o ) => deleteQualityMetric( p, o ), + const removeQualityMetricMutation = useAuthenticatedMutation( + ( deleteParams, options ) => deleteQualityMetric( deleteParams, options ), { - onSuccess: () => { - // fetch updated quality metrics with updated votes - mutate( fetchMetricsParams ); + onSuccess: async ( ) => { + await refetchQualityMetrics( ); + await refetchRemoteObservation( ); + setNotLoading( ); }, - onError: () => { + onError: error => { + logger.error( "removeQualityMetricMutation failed", error ); setHideErrorSheet( false ); } } @@ -197,7 +188,7 @@ const DQAContainer = ( ): React.Node => { metric, ttyl: -1 }; - createRemoveQualityMetricMutation.mutate( qualityMetricParams ); + removeQualityMetricMutation.mutate( qualityMetricParams ); }; // The quality metric "needs_id" uses a fave/unfave vote with vote_scope: "needs_id" diff --git a/src/components/ObsDetails/DataQualityAssessment.js b/src/components/ObsDetails/DataQualityAssessment.js index f8265283f..635368e72 100644 --- a/src/components/ObsDetails/DataQualityAssessment.js +++ b/src/components/ObsDetails/DataQualityAssessment.js @@ -121,6 +121,8 @@ const DataQualityAssessment = ( { ); } + // console.log( "[DEBUG DataQualityAssessment.js] qualityMetrics?.date: ", qualityMetrics?.date ); + return ( diff --git a/tests/integration/DataQualityAssesment/DataQualityAssessment.test.js b/tests/integration/DataQualityAssesment/DataQualityAssessment.test.js index e4f60f55c..b11d8291f 100644 --- a/tests/integration/DataQualityAssesment/DataQualityAssessment.test.js +++ b/tests/integration/DataQualityAssesment/DataQualityAssessment.test.js @@ -32,6 +32,13 @@ jest.mock( "sharedHooks/useCurrentUser", ( ) => ( { } ) ) } ) ); +jest.mock( "sharedHooks/useAuthenticatedQuery", () => ( { + __esModule: true, + default: () => ( { + data: [] + } ) +} ) ); + const mockMutate = jest.fn(); jest.mock( "sharedHooks/useAuthenticatedMutation", () => ( { __esModule: true, @@ -51,31 +58,32 @@ useRoute.mockImplementation( ( ) => ( { } } ) ); +async function expectMutateToHaveBeenCalled() { + expect( await mockMutate ).toHaveBeenCalled(); + // Since we mocked the mutate() method, we're expecting mutation not to + // succeed. We want to wait for this so there are no extra things happening + // outside of act() + await screen.findByText( "ERROR LOADING IN DQA" ); +} + describe( "DQA Vote Buttons", ( ) => { test( "renders DQA vote buttons", async ( ) => { renderComponent( ); - const emptyDisagreeButtons = await screen.findAllByTestId( "DQAVoteButton.EmptyDisagree" ); - fireEvent.press( emptyDisagreeButtons[0] ); - - expect( await mockMutate ).toHaveBeenCalled(); + expect( emptyDisagreeButtons ).toBeTruthy( ); } ); test( "calls api when DQA disagree button is pressed", async ( ) => { renderComponent( ); - const emptyDisagreeButtons = await screen.findAllByTestId( "DQAVoteButton.EmptyDisagree" ); fireEvent.press( emptyDisagreeButtons[0] ); - - expect( await mockMutate ).toHaveBeenCalled(); + await expectMutateToHaveBeenCalled(); } ); test( "calls api when DQA agree button is pressed", async ( ) => { renderComponent( ); - const emptyDisagreeButtons = await screen.findAllByTestId( "DQAVoteButton.EmptyAgree" ); fireEvent.press( emptyDisagreeButtons[0] ); - - expect( await mockMutate ).toHaveBeenCalled(); + await expectMutateToHaveBeenCalled(); } ); } ); diff --git a/tests/unit/components/ObsDetails/DataQualityAssessment.test.js b/tests/unit/components/ObsDetails/DataQualityAssessment.test.js index 33df66243..9b6368d86 100644 --- a/tests/unit/components/ObsDetails/DataQualityAssessment.test.js +++ b/tests/unit/components/ObsDetails/DataQualityAssessment.test.js @@ -33,6 +33,13 @@ jest.mock( "sharedHooks/useCurrentUser", ( ) => ( { } ) ) } ) ); +jest.mock( "sharedHooks/useAuthenticatedQuery", () => ( { + __esModule: true, + default: () => ( { + data: [] + } ) +} ) ); + const mockMutate = jest.fn(); jest.mock( "sharedHooks/useAuthenticatedMutation", () => ( { __esModule: true, @@ -46,6 +53,15 @@ jest.mock( "sharedHooks/useLocalObservation", () => ( { default: jest.fn( ( ) => mockObservation ) } ) ); +jest.mock( "sharedHooks/useRemoteObservation", ( ) => ( { + __esModule: true, + default: ( _uuid, _fetchRemoteEnabled ) => ( { + remoteObservation: mockObservation, + refetchRemoteObservation: jest.fn( ), + isRefetching: false + } ) +} ) ); + useRoute.mockImplementation( ( ) => ( { params: { observationUUID: mockObservation.uuid