fix(build): isolate time tests by Docker build context
All checks were successful
Build and Release FEDEO / verify (push) Successful in 1m0s
Build and Release FEDEO / build-and-release (push) Successful in 6m4s

This commit is contained in:
2026-10-07 19:02:23 +02:00
parent c2c6ca8fe9
commit 15e480ee9a
3 changed files with 61 additions and 18 deletions

View File

@@ -10,8 +10,6 @@ import { TimeService, authorize } from '../src/modules/time-v2/service';
import { TimeMigration, previewLegacy } from '../src/modules/time-v2/migration';
import { legacySpans, installTimeCompatibility, legacyEvent } from '../src/modules/time-v2/compatibility';
import timeV2Routes from '../src/routes/staff/time-v2';
import { timeSpanInput } from '../../frontend/utils/timeSpanInput';
import { staffTimeRows, workingMinutes } from '../../frontend/utils/staffTimeSpans';
const at = (day: string, time: string) => `${day}T${time}:00Z`;
const work = (start = '2026-10-01T06:00:00Z', end: string | null = '2026-10-01T14:30:00Z') => normalizeSpan({ type: 'work', started_at: start, ended_at: end,
breaks: end ? [{ started_at: '2026-10-01T10:00:00Z', ended_at: '2026-10-01T10:30:00Z' }] : [] });
@@ -189,19 +187,18 @@ test('HTTP routes: validation, permissions, compatibility and migration conflict
await f.close();
}
});
test('editing repeated local times preserves the original instant and rejects ambiguous new inputs', () => {
assert.equal(timeSpanInput('2026-10-25T02:15', 'Europe/Berlin', '2026-10-25T01:15:00.000Z'), '2026-10-25T01:15:00.000Z');
assert.equal(timeSpanInput('2026-10-25T02:15', 'Europe/Berlin', '2026-10-25T00:15:00.000Z'), '2026-10-25T00:15:00.000Z');
assert.throws(() => timeSpanInput('2026-10-25T02:15', 'Europe/Berlin'), /zweimal/);
assert.throws(() => timeSpanInput('2026-03-29T02:15', 'Europe/Berlin'), /existiert nicht/);
assert.equal(timeSpanInput('2026-10-25T01:15', 'UTC'), '2026-10-25T01:15:00.000Z');
});
test('dashboard keeps a paused attendance active and freezes its net working duration', () => {
test('legacy compatibility keeps paused attendance on both work and pause segments', () => {
const s = work(undefined, null); s.id = randomUUID(); s.user_id = randomUUID();
s.breaks = [{started_at:'2026-10-01T10:00:00Z',ended_at:null}];
const entries = staffTimeRows(legacySpans([s]),s.user_id,Date.parse('2026-10-01T11:00:00Z'));
assert.equal(entries.length,1); assert.equal(entries[0].type,'work');
assert.equal((entries[0] as any).paused,true);assert.equal(entries[0].stopped_at,null);
assert.equal(workingMinutes(entries[0],Date.parse('2026-10-01T12:00:00Z')),240);
s.breaks = [{ started_at: '2026-10-01T10:00:00Z', ended_at: null }];
const segments = legacySpans([s]);
assert.equal(segments.length, 2);
assert.equal(segments[0].type, 'work');
assert.equal(segments[0].endedAt, s.breaks[0].started_at);
assert.equal(segments[1].type, 'pause');
assert.equal(segments[1].endedAt, null);
for (const segment of segments) {
assert.equal(segment.model, 'spans-v2');
assert.equal(segment.id, s.id);
assert.deepEqual(segment.attendance, s);
}
});

View File

@@ -13,7 +13,7 @@ ARG FEDEO_VERSION=0.0.0-dev
ARG FEDEO_REVISION=unknown
ENV FEDEO_VERSION=$FEDEO_VERSION
ENV FEDEO_REVISION=$FEDEO_REVISION
RUN npm run build
RUN node --test tests/time-v2.test.cjs && npm run build
# --- Stage 2: Runtime ---
FROM node:22-alpine AS runner

View File

@@ -0,0 +1,46 @@
const assert = require('node:assert/strict')
const test = require('node:test')
const fs = require('node:fs')
const vm = require('node:vm')
const ts = require('typescript')
function loadUtility(name) {
const source = fs.readFileSync(`${__dirname}/../utils/${name}.ts`, 'utf8')
const { outputText } = ts.transpileModule(source, {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2021 },
})
const exports = {}
vm.runInNewContext(outputText, { exports })
return exports
}
const { timeSpanInput } = loadUtility('timeSpanInput')
const { staffTimeRows, workingMinutes } = loadUtility('staffTimeSpans')
test('editing repeated local times preserves the original instant and rejects ambiguous new inputs', () => {
assert.equal(timeSpanInput('2026-10-25T02:15', 'Europe/Berlin', '2026-10-25T01:15:00.000Z'), '2026-10-25T01:15:00.000Z');
assert.equal(timeSpanInput('2026-10-25T02:15', 'Europe/Berlin', '2026-10-25T00:15:00.000Z'), '2026-10-25T00:15:00.000Z');
assert.throws(() => timeSpanInput('2026-10-25T02:15', 'Europe/Berlin'), /zweimal/);
assert.throws(() => timeSpanInput('2026-03-29T02:15', 'Europe/Berlin'), /existiert nicht/);
assert.equal(timeSpanInput('2026-10-25T01:15', 'UTC'), '2026-10-25T01:15:00.000Z');
});
test('dashboard keeps a paused attendance active and freezes its net working duration', () => {
const attendance = {
id: 'attendance-1', user_id: 'user-1', type: 'work', status: 'factual',
started_at: '2026-10-01T06:00:00Z', ended_at: null,
breaks: [{ started_at: '2026-10-01T10:00:00Z', ended_at: null }],
}
const base = { id: attendance.id, model: 'spans-v2', attendance }
const segments = [
{ ...base, type: 'work', startedAt: attendance.started_at, endedAt: attendance.breaks[0].started_at },
{ ...base, type: 'pause', startedAt: attendance.breaks[0].started_at, endedAt: null },
]
const entries = staffTimeRows(segments, attendance.user_id, Date.parse('2026-10-01T11:00:00Z'))
assert.equal(entries.length, 1)
assert.equal(entries[0].type, 'work')
assert.equal(entries[0].paused, true)
assert.equal(entries[0].stopped_at, null)
assert.equal(entries[0].duration_minutes, 240)
assert.equal(workingMinutes(entries[0], Date.parse('2026-10-01T12:00:00Z')), 240)
})