ci: Backend-e2e als eigener Workflow mit Postgres-Service
backend-e2e.yml läuft bei Änderungen unter ApiCore-Backend/ gegen einen Wegwerf-Postgres 18.6 (per Digest), mit frisch erzeugten JWT-Secrets und SKIP_EXTERNAL=1 für den Wetter-Test gegen die echte API. Der Herdentest prüft globalen Zustand, den parallele Suites verändern; er wiederholt die herdenabhängigen Fälle bis zu dreimal aus einem zurückgesetzten Zustand. Lokal 3 volle parallele Läufe grün (103 Suites, 1073 Tests). Refs #32 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
279ceec328
commit
291ec1d7ff
3 files changed
+265
-94
No files matched your search
@@ -24,6 +24,10 @@ interface TrachtprognoseBody {
|
||||
historicalAverageYieldKg: number | null;
|
||||
}
|
||||
|
||||
// These two cases call the real Open-Meteo API. CI sets SKIP_EXTERNAL=1 so the
|
||||
// pipeline does not depend on the internet; locally they run as before.
|
||||
const itExternal = process.env.SKIP_EXTERNAL === '1' ? it.skip : it;
|
||||
|
||||
describe('Weather (e2e)', () => {
|
||||
let app: INestApplication<App>;
|
||||
let prisma: PrismaService;
|
||||
@@ -75,32 +79,40 @@ describe('Weather (e2e)', () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
it('returns real daily weather for an apiary with coordinates', async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v1/apiaries/${apiaryWithCoordsId}/weather`)
|
||||
.set('Authorization', `Bearer ${beekeeperToken}`)
|
||||
.expect(200);
|
||||
itExternal(
|
||||
'returns real daily weather for an apiary with coordinates',
|
||||
async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v1/apiaries/${apiaryWithCoordsId}/weather`)
|
||||
.set('Authorization', `Bearer ${beekeeperToken}`)
|
||||
.expect(200);
|
||||
|
||||
const body = response.body as WeatherBody;
|
||||
expect(Array.isArray(body.daily)).toBe(true);
|
||||
expect(body.daily.length).toBeGreaterThan(15);
|
||||
const today = body.daily[0];
|
||||
expect(today.date).toEqual(expect.stringMatching(/^\d{4}-\d{2}-\d{2}$/));
|
||||
}, 15000);
|
||||
const body = response.body as WeatherBody;
|
||||
expect(Array.isArray(body.daily)).toBe(true);
|
||||
expect(body.daily.length).toBeGreaterThan(15);
|
||||
const today = body.daily[0];
|
||||
expect(today.date).toEqual(expect.stringMatching(/^\d{4}-\d{2}-\d{2}$/));
|
||||
},
|
||||
15000,
|
||||
);
|
||||
|
||||
it('returns a Trachtprognose with a valid rating for an apiary with coordinates', async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v1/apiaries/${apiaryWithCoordsId}/trachtprognose`)
|
||||
.set('Authorization', `Bearer ${beekeeperToken}`)
|
||||
.expect(200);
|
||||
itExternal(
|
||||
'returns a Trachtprognose with a valid rating for an apiary with coordinates',
|
||||
async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.get(`/api/v1/apiaries/${apiaryWithCoordsId}/trachtprognose`)
|
||||
.set('Authorization', `Bearer ${beekeeperToken}`)
|
||||
.expect(200);
|
||||
|
||||
const body = response.body as TrachtprognoseBody;
|
||||
expect(['GUT', 'MAESSIG', 'SCHWACH', 'KEINE_TRACHT']).toContain(
|
||||
body.rating,
|
||||
);
|
||||
expect(body.season).toEqual(expect.any(String));
|
||||
expect(body.reasoning.length).toBeGreaterThan(0);
|
||||
}, 15000);
|
||||
const body = response.body as TrachtprognoseBody;
|
||||
expect(['GUT', 'MAESSIG', 'SCHWACH', 'KEINE_TRACHT']).toContain(
|
||||
body.rating,
|
||||
);
|
||||
expect(body.season).toEqual(expect.any(String));
|
||||
expect(body.reasoning.length).toBeGreaterThan(0);
|
||||
},
|
||||
15000,
|
||||
);
|
||||
|
||||
it('rejects weather requests for an apiary without coordinates', () => {
|
||||
return request(app.getHttpServer())
|
||||
|
||||
Reference in new issue
Block a user