d606f8371c
Ports the weather check added to stroy-bot-main on 2026-10-16: daily station weather, report positions with weather per shift and the AI assessment of working conditions. Opens as ?page=weather&start=&end= instead of the #weathercheck hash, and hub dates survive the way back. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
63 lines
2.6 KiB
TypeScript
63 lines
2.6 KiB
TypeScript
import { fetchWeatherCheck, requestWeatherAssessment, WEATHER_PATHS } from './weatherRepository';
|
|
import { IWeatherPosition, Nullable } from './weatherTypes';
|
|
import { createFakeHttpClient } from '../../shared/testing/fakeHttpClient';
|
|
|
|
const API = 'https://api.tnsu.kz';
|
|
const PERIOD = { start: '2026-10-01', end: '2026-10-07' };
|
|
|
|
const position = (profession: string, assessment: Nullable<string> = null): IWeatherPosition => ({
|
|
project: 'ТЕСТ',
|
|
profession,
|
|
date: '2026-10-01',
|
|
work_type: 'Бетонирование',
|
|
hours: 8,
|
|
hours_type: null,
|
|
headcount: 2,
|
|
shift: '1',
|
|
shift_start: '08:00',
|
|
shift_end: '20:00',
|
|
weather: null,
|
|
assessment,
|
|
comment: null,
|
|
downtime_act_recommended: null,
|
|
downtime_act_reason: null
|
|
});
|
|
|
|
describe('адреса сверки погоды (1:1 со stroy-bot-main)', () => {
|
|
it('период — Unix-секунды UTC: 00:00:00 первого дня и 23:59:59 последнего', () => {
|
|
expect(WEATHER_PATHS.check(API, 51, PERIOD)).toEqual(
|
|
'https://api.tnsu.kz/Report/StroyBot/WeatherCheck?start=1790812800&end=1791417599&projectId=51'
|
|
);
|
|
});
|
|
|
|
it('оценка ИИ', () => {
|
|
expect(WEATHER_PATHS.assess(API)).toEqual('https://api.tnsu.kz/Report/StroyBot/WeatherCheck/Assess');
|
|
});
|
|
});
|
|
|
|
describe('запросы', () => {
|
|
it('сверка — GET, ответ отдаётся как есть', async () => {
|
|
const body = { project: 'ТЕСТ', days: [], positions: [], notes: [] };
|
|
const client = createFakeHttpClient([{ match: 'WeatherCheck?', response: { body } }]);
|
|
expect(await fetchWeatherCheck(client, API, 51, PERIOD)).toEqual(body);
|
|
expect(client.requests[0].request.method).toBeUndefined();
|
|
});
|
|
|
|
it('ошибка API пробрасывается', async () => {
|
|
const client = createFakeHttpClient([{ match: 'WeatherCheck?', response: { status: 500, body: 'boom' } }]);
|
|
await expect(fetchWeatherCheck(client, API, 51, PERIOD)).rejects.toThrow('500');
|
|
});
|
|
|
|
it('оценка — POST со всеми позициями в теле { positions }', async () => {
|
|
const result = { assessed: 1, skipped: 0, positions: [position('Бетонщик', 'В пределах нормы')] };
|
|
const client = createFakeHttpClient([{ match: '/Assess', response: { body: result } }]);
|
|
|
|
expect(await requestWeatherAssessment(client, API, [position('Бетонщик')])).toEqual(result);
|
|
|
|
const sent = client.requests[0].request;
|
|
expect(sent.method).toEqual('POST');
|
|
expect(sent.headers).toEqual({ accept: '*/*', 'content-type': 'application/json' });
|
|
expect(JSON.parse(String(sent.body))).toEqual({ positions: [position('Бетонщик')] });
|
|
});
|
|
});
|