A doctor who also owns a clinic runs two environments, and a subscription belongs to an environment, not to the user. The panel treated it as the user's: the subscription query was keyed ['subscription-my'] with no context, and switching environments never touched the react-query cache. So upgrading the clinic left the personal practice showing the clinic's plan with its feature-gated menu items unlocked, and vice versa. The query key now carries the active dbUuid, and the context switch clears the whole cache — every cached response belongs to the environment it was fetched in, not just this one. The API was already correct: DualEnvironmentSubscriptionTest pins that granting one environment leaves the other on free. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
75 lines
2.8 KiB
TypeScript
75 lines
2.8 KiB
TypeScript
import React from 'react';
|
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { renderHook, waitFor } from '@testing-library/react';
|
|
import { QueryClientProvider } from '@tanstack/react-query';
|
|
import { makeClient } from '../test/utils';
|
|
import { useAuthStore } from '../stores/authStore';
|
|
|
|
vi.mock('../lib/api', () => ({
|
|
api: { get: vi.fn() },
|
|
}));
|
|
|
|
import { api } from '../lib/api';
|
|
import { useSubscription } from './useSubscription';
|
|
|
|
const get = api.get as ReturnType<typeof vi.fn>;
|
|
const initial = useAuthStore.getInitialState();
|
|
|
|
function planResponse(name: string) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
subscription: null,
|
|
used_trial: false,
|
|
effective_plan: { name, features: { patient_records: name !== 'free' }, max_secretaries: 1, max_resources: 1 },
|
|
},
|
|
};
|
|
}
|
|
|
|
beforeEach(() => {
|
|
localStorage.clear();
|
|
useAuthStore.setState(initial, true);
|
|
get.mockReset();
|
|
});
|
|
|
|
describe('useSubscription', () => {
|
|
/**
|
|
* پزشکی که هم مطب شخصی دارد و هم کلینیک، دو محیط دارد و اشتراک روی محیط مینشیند.
|
|
* با کلیدِ بدون محیط، پاسخِ cache شدهٔ محیط قبلی در محیط تازه سرو میشد و هر دو
|
|
* محیط ارتقایافته بهنظر میرسیدند.
|
|
*/
|
|
it('پاسخِ cache شدهٔ محیط دیگر را سرو نمیکند', async () => {
|
|
const client = makeClient();
|
|
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
<QueryClientProvider client={client}>{children}</QueryClientProvider>
|
|
);
|
|
|
|
// محیط کلینیک از قبل در cache نشسته است.
|
|
client.setQueryData(['subscription-my', 'clinic-1'], planResponse('professional'));
|
|
|
|
useAuthStore.setState({ primaryRole: 'doctor', dbUuid: 'doctor-1' });
|
|
get.mockResolvedValue(planResponse('free'));
|
|
|
|
const { result } = renderHook(() => useSubscription(), { wrapper });
|
|
|
|
await waitFor(() => expect(result.current.planLoaded).toBe(true));
|
|
expect(result.current.hasFeature('patient_records')).toBe(false);
|
|
expect(get).toHaveBeenCalledWith('/api/v1/subscription/my');
|
|
});
|
|
|
|
it('در همان محیط، پاسخِ cache شده دوباره درخواست نمیشود', async () => {
|
|
const client = makeClient();
|
|
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
<QueryClientProvider client={client}>{children}</QueryClientProvider>
|
|
);
|
|
|
|
client.setQueryData(['subscription-my', 'clinic-1'], planResponse('professional'));
|
|
useAuthStore.setState({ primaryRole: 'clinic', dbUuid: 'clinic-1' });
|
|
|
|
const { result } = renderHook(() => useSubscription(), { wrapper });
|
|
|
|
await waitFor(() => expect(result.current.hasFeature('patient_records')).toBe(true));
|
|
expect(get).not.toHaveBeenCalled();
|
|
});
|
|
});
|