chain-studio-flow-editor/test/flow_project_test.dart
flemming-it c4a39a3779 feat: project separation in the flow list (0.25.0)
Filter the file list by the host's active project — flows without
a project: key count as 'general', display-only, the file is never
rewritten. New flows are stamped with the active project's key
(general and all-projects stay unstamped). Adds a toolbarTrailing
slot so the host can mount its workspace switcher in the editor's
single toolbar, and a flowsDir injection point so widget tests run
against a temp dir instead of the operator's ~/.chain flows.
Covered by pure filter-semantics tests plus hermetic widget tests
for filtering, the project-empty state, and new-flow stamping.

Signed-off-by: flemming-it <sf@flemming.it>
2026-07-22 13:56:29 +02:00

71 lines
2.5 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:chain_studio_flow_editor/src/flow_project.dart';
void main() {
group('parseFlowProject', () {
test('reads a bare top-level project key', () {
const yaml = 'name: demo\nproject: client-a\nsteps: []\n';
expect(parseFlowProject(yaml), 'client-a');
});
test('strips quotes and normalizes casing/spaces', () {
expect(parseFlowProject('project: "Client A"'), 'client-a');
// Non-[a-z0-9] that isn't a separator is dropped without a
// dash — matches the hub's normalize_project_slug.
expect(parseFlowProject("project: 'Recl∆Im'"), 'reclim');
});
test('returns empty when no top-level project is declared', () {
const yaml = 'name: demo\ninputs:\n topic: text\nsteps: []\n';
expect(parseFlowProject(yaml), '');
});
test('ignores an indented project inside a step with-block', () {
const yaml =
'name: demo\nsteps:\n - id: s\n use: x@^0\n with:\n project: not-this\n';
expect(parseFlowProject(yaml), '');
});
test('a top-level project still wins over a later nested one', () {
const yaml =
'project: top\nsteps:\n - id: s\n with:\n project: nested\n';
expect(parseFlowProject(yaml), 'top');
});
});
group('project filter semantics', () {
test('no project key counts as general (display only)', () {
expect(effectiveFlowProject(''), 'general');
expect(effectiveFlowProject('client-a'), 'client-a');
});
test('empty active workspace shows every flow', () {
expect(flowVisibleInProject('', ''), isTrue);
expect(flowVisibleInProject('client-a', ''), isTrue);
});
test('general shows keyless flows and explicit general ones', () {
expect(flowVisibleInProject('', 'general'), isTrue);
expect(flowVisibleInProject('general', 'general'), isTrue);
expect(flowVisibleInProject('client-a', 'general'), isFalse);
});
test('a project shows only its own flows', () {
expect(flowVisibleInProject('client-a', 'client-a'), isTrue);
expect(flowVisibleInProject('', 'client-a'), isFalse);
expect(flowVisibleInProject('client-b', 'client-a'), isFalse);
});
});
group('normalizeProjectSlug', () {
test('collapses separators and trims trailing dashes', () {
expect(normalizeProjectSlug('Projekt Alpha__'), 'projekt-alpha');
expect(normalizeProjectSlug('a - b - c'), 'a-b-c');
});
test('empty stays empty', () {
expect(normalizeProjectSlug(' '), '');
});
});
}