mirror of
https://github.com/directus/directus.git
synced 2026-01-26 06:28:00 -05:00
Fix page tracking debounced timeout (#16552)
* fix trackPage timeout resets * tweak test
This commit is contained in:
141
app/src/router.test.ts
Normal file
141
app/src/router.test.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { setActivePinia } from 'pinia';
|
||||
|
||||
import { useAppStore } from '@/stores/app';
|
||||
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
|
||||
import { defineComponent, h } from 'vue';
|
||||
import { createMemoryHistory, createRouter, Router } from 'vue-router';
|
||||
|
||||
const testComponent = defineComponent({
|
||||
render: () => h('div'),
|
||||
});
|
||||
|
||||
const nonPublicRoutes = ['first', 'second', 'third'].map((route) => ({
|
||||
name: route,
|
||||
path: `/${route}`,
|
||||
component: testComponent,
|
||||
meta: {}, // make sure 'meta.public' is not set so that they are tracked
|
||||
}));
|
||||
|
||||
let router: Router;
|
||||
const authRefresh = vi.fn();
|
||||
const userStoreTrackPage = vi.fn();
|
||||
|
||||
vi.mock('@/auth', () => ({
|
||||
refresh: authRefresh,
|
||||
}));
|
||||
|
||||
vi.mock('@/hydrate', () => ({
|
||||
hydrate: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@/stores/server', () => ({
|
||||
useServerStore: vi.fn().mockReturnValue({
|
||||
info: {
|
||||
project: null,
|
||||
},
|
||||
hydrate: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@/stores/user', () => ({
|
||||
useUserStore: vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
trackPage: userStoreTrackPage,
|
||||
};
|
||||
}),
|
||||
}));
|
||||
|
||||
beforeEach(async () => {
|
||||
setActivePinia(
|
||||
createTestingPinia({
|
||||
createSpy: vi.fn,
|
||||
})
|
||||
);
|
||||
|
||||
const importedRouter = await import('./router');
|
||||
|
||||
router = createRouter({
|
||||
history: createMemoryHistory(), // intentionally use memory for tests
|
||||
routes: [...importedRouter.defaultRoutes, ...nonPublicRoutes],
|
||||
});
|
||||
|
||||
router.beforeEach(importedRouter.onBeforeEach);
|
||||
router.afterEach(importedRouter.onAfterEach);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Ensure the internal firstLoad variable in the imported router
|
||||
// is reset before every test
|
||||
vi.resetModules();
|
||||
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('onBeforeEach', () => {
|
||||
test('should try retrieving a fresh access token on first load', async () => {
|
||||
router.push('/');
|
||||
await router.isReady();
|
||||
|
||||
expect(authRefresh).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
test('should not try retrieving a fresh access token after the first load', async () => {
|
||||
router.push('/');
|
||||
await router.isReady();
|
||||
|
||||
// clear calls since there was an initial auth refresh
|
||||
authRefresh.mockClear();
|
||||
|
||||
await router.push('/login');
|
||||
|
||||
expect(authRefresh).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should not try retrieving a fresh access token after the first load', async () => {
|
||||
router.push('/');
|
||||
await router.isReady();
|
||||
|
||||
// clear calls since there was an initial auth refresh
|
||||
authRefresh.mockClear();
|
||||
|
||||
await router.push('/login');
|
||||
|
||||
expect(authRefresh).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('onAfterEach', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
test('should not trackPage for public routes', async () => {
|
||||
router.push('/');
|
||||
await router.isReady();
|
||||
|
||||
expect(userStoreTrackPage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should only trackPage once when routing multiple times before the setTimeout duration ends', async () => {
|
||||
router.push('/');
|
||||
await router.isReady();
|
||||
|
||||
// mock authenticated to prevent redirection back to login page
|
||||
const appStore = useAppStore();
|
||||
appStore.hydrated = true;
|
||||
appStore.authenticated = true;
|
||||
|
||||
for (const route of nonPublicRoutes.map((route) => route.path)) {
|
||||
await router.push(route);
|
||||
}
|
||||
|
||||
// advance past the trackTimeout duration
|
||||
vi.advanceTimersByTime(1000);
|
||||
expect(userStoreTrackPage).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
@@ -153,11 +153,11 @@ export const onAfterEach: NavigationHookAfter = (to) => {
|
||||
// this call while more important things are loading
|
||||
|
||||
if (trackTimeout) {
|
||||
clearTimeout(trackTimeout);
|
||||
window.clearTimeout(trackTimeout);
|
||||
trackTimeout = null;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
trackTimeout = window.setTimeout(() => {
|
||||
userStore.trackPage(to.fullPath);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user