-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: tests & react query cache keys #3540
Conversation
const { storeQuery } = useNotifications(); | ||
const { updateAction } = useUpdateAction({ query: storeQuery }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure is it is the best way to do so, but at the moment we need to pass the query to the cache key..
@djabarovgeorge left you a dm in the Discord, let's not merge this and chat about the changes |
…ifier, subscriberId, subscriberHash changes
.github/workflows/test.yml
Outdated
@@ -157,7 +157,7 @@ jobs: | |||
- uses: actions/checkout@v3 | |||
- uses: ./.github/actions/setup-project | |||
- uses: mansagroup/nrwl-nx-action@v3 | |||
if: ${{matrix.projectName == '@novu/application-generic' }} | |||
if: ${{matrix.projectName == '@novu/application-generic' || matrix.projectName == '@novu/notification-center'}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when there are the changes in the notification-center
package then run the tests pipeline: lint, build, test
"@testing-library/react": "^11.1.0", | ||
"@testing-library/dom": "^9.3.0", | ||
"@testing-library/user-event": "^12.1.10", | ||
"@testing-library/jest-dom": "^4.2.4", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RTL for the notification-center
package... I've added a couple of the unit/integration tests
const [sessionInfo, setSessionInfo] = useState({ | ||
isSessionInitialized: false, | ||
applicationIdentifier, | ||
subscriberId, | ||
subscriberHash, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
created the state for the data that is needed to initialize the session...
@@ -81,9 +86,9 @@ export function NovuProvider({ | |||
(newSession: ISession) => { | |||
applyToken({ apiService, token: newSession.token }); | |||
initializeSocket(newSession); | |||
setSessionInitialized(true); | |||
setSessionInfo((old) => ({ ...old, isSessionInitialized: true })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the callback called when the session is initialized... setting this flag to true will result in fetching the org, unseen count, and notifications...
useEffect(() => { | ||
setSessionInfo((old) => ({ | ||
...old, | ||
isSessionInitialized: false, | ||
applicationIdentifier, | ||
subscriberId, | ||
subscriberHash, | ||
})); | ||
logout(); | ||
queryClient.refetchQueries([...SESSION_QUERY_KEY, applicationIdentifier, subscriberId, subscriberHash]); | ||
}, [logout, subscriberId, applicationIdentifier, subscriberHash]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when the props subscriberId, applicationIdentifier, subscriberHash
are changing, set the session to isSessionInitialized: false
and then reinitialize the session
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean that the reinitialize will be in onSuccessfulSession?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
|
||
export const useFeedUnseenCount = ( | ||
{ query }: { query?: IStoreQuery }, | ||
options: UseQueryOptions<ICountData, Error, ICountData> = {} | ||
) => { | ||
const { apiService, isSessionInitialized } = useNovuContext(); | ||
const setQueryKey = useSetQueryKey(); | ||
const feedUnseenCountQueryKey = useFeedUnseenCountQueryKey(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
created a few helper hooks that do return the query keys... the hooks are reused in a couple places
|
||
const PROMISE_TIMEOUT = 150; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know why but increasing the timeout helps tests to pass :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder how hard was figuring it out 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I knew that the tests are correct, so wasn't that hard :)
<StoreProvider stores={stores}> | ||
<NotificationsProviderInternal>{children}</NotificationsProviderInternal> | ||
</StoreProvider> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
basically, I've created the new StoreProvider
that allows us to use the storeQuery
state inside of any public hooks like useUnseenCountQueryKey
... this way we don't require the hook users to pass it through props... it's an internal state info
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing reason to refactor :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As always amazing work and amazing addition tests left a couple of questions regarding things I was not sure about. @LetItRock
}, | ||
[apiService, setSessionInitialized, initializeSocket] | ||
[apiService, setSessionInfo, initializeSocket] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the difference between adding here setSessionInfo instead of sessionInfo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setSessionInfo
is a state setter ;)
setSessionInitialized(false); | ||
}, [removeToken, disconnectSocket, apiService]); | ||
setSessionInfo((old) => ({ ...old, isSessionInitialized: false })); | ||
}, [setSessionInfo, disconnectSocket, apiService]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removeToken is not needed anymore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed because it's a util that never changes ;)
); | ||
|
||
useEffect(() => disconnectSocket, [disconnectSocket]); | ||
|
||
useEffect(() => { | ||
setSessionInfo((old) => ({ | ||
...old, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need ...old,
? won't it will be overridden by the following params, or did you add for future proof if we will add more params to setSessionInfo object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, it's always better to do it for the future changes, like this way I won't need to revisit every setSessionInfo
call
useEffect(() => { | ||
setSessionInfo((old) => ({ | ||
...old, | ||
isSessionInitialized: false, | ||
applicationIdentifier, | ||
subscriberId, | ||
subscriberHash, | ||
})); | ||
logout(); | ||
queryClient.refetchQueries([...SESSION_QUERY_KEY, applicationIdentifier, subscriberId, subscriberHash]); | ||
}, [logout, subscriberId, applicationIdentifier, subscriberHash]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean that the reinitialize will be in onSuccessfulSession?
|
||
export const useFetchUserPreferencesQueryKey = () => { | ||
const setQueryKey = useSetQueryKey(); | ||
const queryKey = useMemo(() => setQueryKey(USER_PREFERENCES_QUERY_KEY), [setQueryKey]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const queryKey = useMemo(() => setQueryKey(USER_PREFERENCES_QUERY_KEY), [setQueryKey]); | |
const queryKey = useMemo(() => setQueryKey([...USER_PREFERENCES_QUERY_KEY]), [setQueryKey]); |
|
||
const PROMISE_TIMEOUT = 150; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder how hard was figuring it out 😅
jest.clearAllMocks(); | ||
queryClient.clear(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏
<StoreProvider stores={stores}> | ||
<NotificationsProviderInternal>{children}</NotificationsProviderInternal> | ||
</StoreProvider> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing reason to refactor :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤩
60f2bf4
to
19bc37e
Compare
import { FEED_UNSEEN_COUNT_QUERY_KEY } from './queryKeys'; | ||
import { useSetQueryKey } from './useSetQueryKey'; | ||
|
||
export const useFeedUnseenCountQueryKey = (query?: IStoreQuery) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I am following up, in this case, we can not get the query inside this hook from the useStore hook?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this hook is used in the useFeedUnseenCount
which is used for every feed tab, which passes it's storeQuery
to the hook useFeedUnseenCount
--> useFeedUnseenCountQueryKey
…tions from the pr #3540
What change does this PR introduce?
Fix the test.
Add the query to the cache key on all the cases.
Why was this change needed?
At the moment INFINITE_NOTIFICATIONS_QUERY_KEY could get the query object in useFetchNotifications but in other places, it was missing, which caused issues.
Other information (Screenshots)