Added tests with storybook and like API call with service interrupt test

This commit is contained in:
2026-06-17 15:36:27 -07:00
parent d42b11381f
commit f944c3aac6
8 changed files with 1093 additions and 31 deletions
@@ -1,13 +1,16 @@
import { useMemo } from 'react';
import { Box, Flex, Text } from '@chakra-ui/react';
import { Box, Flex, Spinner, Text } from '@chakra-ui/react';
import Plot from 'react-plotly.js';
import VdapApi from '../../hooks/useVdapApi.js'; // Adjust path as needed
export default function VaaActivity7Day() {
// ONE LINE to handle all fetching, loading, and error states!
const { data: apiData, isLoading, error } = VdapApi('/api/v2/comm_coor_vaa');
export default function VaaActivityChart({ data = [] }) {
// Transform flat database rows into Plotly's required "Traces"
const plotTraces = useMemo(() => {
if (!data || data.length === 0) return [];
if (!apiData || apiData.length === 0) return [];
const groupedData = data.reduce((acc, curr) => {
const groupedData = apiData.reduce((acc, curr) => {
const name = curr.volc_name || 'Unknown';
if (!acc[name]) acc[name] = { x: [], y: [], text: [] };
@@ -27,21 +30,31 @@ export default function VaaActivityChart({ data = [] }) {
hoverinfo: 'text',
marker: { size: 8, line: { width: 1, color: 'white' } }
}));
}, [data]);
}, [apiData]);
if (plotTraces.length === 0) {
return (
<Flex height="100%" width="100%" align="center" justify="center" bg="gray.800" borderRadius="md">
<Text color="gray.400">No flight level data available.</Text>
</Flex>
);
}
if (isLoading) return (
<Flex w="100%" h="100%" bg="gray.800" borderRadius="md" align="center" justify="center">
<Spinner size="xl" color="blue.400" thickness="4px" />
</Flex>
);
if (error) return (
<Flex w="100%" h="100%" bg="gray.800" borderRadius="md" align="center" justify="center" p={4}>
<Text color="red.400">{error}</Text>
</Flex>
);
if (plotTraces.length === 0) return (
<Flex height="100%" width="100%" align="center" justify="center" bg="gray.800" borderRadius="md">
<Text color="gray.400">No flight level data available.</Text>
</Flex>
);
return (
<Box height="100%" width="100%" bg="gray.800" borderRadius="md" overflow="hidden">
<Plot
data={plotTraces}
useResizeHandler={true} // Crucial for reacting to grid drags
useResizeHandler={true}
style={{ width: '100%', height: '100%' }}
layout={{
autosize: true,
@@ -1,5 +1,6 @@
import React from 'react';
import { Box } from '@chakra-ui/react';
import { http, HttpResponse } from 'msw'; // Import MSW
import VaaActivity7Day from './VaaActivity7Day.jsx';
export default {
@@ -25,10 +26,47 @@ const mockData = [
{ volc_name: "Popocatepetl", obs_va_epoch: Date.now() - 86400000 * 1, obs_fl: 200 }
];
// Scenario LIVE: call our API for real
export const LivePopulated = {};
// Scenario 1: Successful API Call
export const Populated = {
args: { data: mockData },
parameters: {
msw: {
handlers: [
// Intercept the exact URL your component is trying to fetch
http.get('*/api/v2/dvar_vaa', () => {
// Return a 200 OK with the mock JSON
return HttpResponse.json(mockData);
}),
],
},
},
};
export const EmptyState = {
args: { data: [] },
// Scenario 2: The 500 Server Crash
export const ServerCrash = {
parameters: {
msw: {
handlers: [
http.get('*/api/v2/dvar_vaa', () => {
// Return a 500 Error
return new HttpResponse(null, { status: 500 });
}),
],
},
},
};
// Scenario 3: Empty State (API works, but no data returned)
export const EmptyData = {
parameters: {
msw: {
handlers: [
http.get('*/api/v2/dvar_vaa', () => {
return HttpResponse.json([]);
}),
],
},
},
};
+43
View File
@@ -0,0 +1,43 @@
import { useState, useEffect } from 'react';
export default function useWidgetApi(endpoint) {
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
setError(null);
try {
const baseUrl = import.meta.env.VITE_API_BASE_URL || 'http://web-api:8000';
// Strip leading slashes to prevent double slashes in the URL
const cleanEndpoint = endpoint.startsWith('/') ? endpoint.slice(1) : endpoint;
const url = `${baseUrl}/${cleanEndpoint}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`API Error: ${response.status}`);
}
const json = await response.json();
const responseData = Array.isArray(json) ? json : json.data;
setData(responseData || []);
} catch (err) {
console.error(`Failed to fetch from ${endpoint}:`, err);
setError("Failed to load widget data. Is the Django API running?");
} finally {
setIsLoading(false);
}
};
if (endpoint) {
fetchData();
}
}, [endpoint]); // Re-fetch if the endpoint changes
return { data, isLoading, error };
}