fix(plugins): stop automatic detail retry loop
This commit is contained in:
@@ -348,6 +348,75 @@ describe('PluginsView', () => {
|
||||
expect(screen.getAllByRole('alert')).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('attempts a rejected official detail load once per open and retries only after close and reopen', async () => {
|
||||
preparePluginsRouteState();
|
||||
pluginMarketplaceStore.setState({
|
||||
catalog: {
|
||||
items: [{
|
||||
pluginId: 'makelore.notes',
|
||||
title: 'Notes',
|
||||
summary: 'Write project notes',
|
||||
category: 'productivity',
|
||||
tags: ['notes'],
|
||||
providerDisplayName: 'MakeLore',
|
||||
runtimeKind: 'skill_only',
|
||||
runtimeStatus: 'enabled',
|
||||
acquisition: 'free',
|
||||
usageBilling: 'token_point',
|
||||
includedOperationCount: 0,
|
||||
meteredOperationCount: 1,
|
||||
stableVersion: '2.0.0',
|
||||
betaVersion: null,
|
||||
}],
|
||||
nextCursor: null,
|
||||
total: 1,
|
||||
catalogGeneration: 1,
|
||||
etag: 'catalog-1',
|
||||
pricingVersionId: 'pricing-1',
|
||||
stale: false,
|
||||
fetchedAt: 1,
|
||||
},
|
||||
});
|
||||
|
||||
let rejectFirstAttempt: (reason?: unknown) => void = () => undefined;
|
||||
const firstAttempt = new Promise<void>((_resolve, reject) => {
|
||||
rejectFirstAttempt = reject;
|
||||
});
|
||||
const loadDetail = vi.spyOn(pluginMarketplaceStore.getState(), 'loadDetail')
|
||||
.mockImplementationOnce(async () => await firstAttempt)
|
||||
.mockResolvedValue(undefined);
|
||||
|
||||
render(
|
||||
<MemoryRouter initialEntries={[
|
||||
'/plugins?scope=all&source=all&state=all&plugin=official%3Amakelore.notes',
|
||||
]}>
|
||||
<Plugins />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
await waitFor(() => expect(loadDetail).toHaveBeenCalledTimes(1));
|
||||
await act(async () => {
|
||||
pluginMarketplaceStore.setState((state) => ({
|
||||
detailState: { ...state.detailState, 'makelore.notes': 'error' },
|
||||
catalogError: 'detail offline',
|
||||
}));
|
||||
rejectFirstAttempt(new Error('detail offline'));
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
});
|
||||
expect(loadDetail).toHaveBeenCalledTimes(1);
|
||||
expect(screen.getByRole('alert', { hidden: true })).toHaveTextContent('插件详情刷新失败。 detail offline');
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '关闭插件详情' }));
|
||||
await waitFor(() => expect(screen.queryByRole('dialog', { name: 'Notes' })).not.toBeInTheDocument());
|
||||
fireEvent.click(screen.getByRole('button', { name: '查看Notes详情' }));
|
||||
await waitFor(() => expect(loadDetail).toHaveBeenCalledTimes(2));
|
||||
});
|
||||
|
||||
it('renders the unified workspace and exposes URL-backed filter changes', () => {
|
||||
const view = props();
|
||||
view.sourceErrors = [
|
||||
|
||||
Reference in New Issue
Block a user