Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:querya_desktop/core/database/table_mutation_engine.dart';

import '../../support/fake_table_data_delegate.dart';
import '../../support/generic_table_view_harness.dart';
import '../helpers/e2e_grid_interactions.dart';

const _timeout = Timeout(Duration(seconds: 60));

/// `pumpAndSettle` never returns while a save runs: the spinner animates.
Future<void> _frames(WidgetTester tester) async {
await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
}

void main() {
// dialect → (quoted table, quoted column)
const quoting = {
SqlDialect.postgres: ('"public"."users"', '"name"'),
SqlDialect.mysql: ('`public`.`users`', '`name`'),
SqlDialect.sqlite: ('"users"', '"name"'),
};

for (final entry in quoting.entries) {
final dialect = entry.key;
final (table, column) = entry.value;

testWidgets('${dialect.name}: UPDATE, INSERT and DELETE are previewed '
'and committed in one plan', timeout: _timeout, (tester) async {
final delegate = FakeTableDataDelegate();
final state = await pumpGenericTableView(
tester,
delegate,
dialect: dialect,
);
await E2eGrid.shortcut(tester, LogicalKeyboardKey.keyE, ctrl: true);
await _frames(tester);

await E2eGrid.doubleTapCell(tester, 'Alice');
await E2eGrid.typeAndCommit(tester, 'Alicia');
await _frames(tester);
await E2eGrid.tapCell(tester, 'Carol');
await tester.tap(find.text('Delete Row'));
await _frames(tester);
await tester.tap(find.text('Add Row'));
await _frames(tester);
E2eGrid.expectStaged(
state.stagingBuffer!,
modifiedCells: 1,
inserted: 1,
deleted: 1,
);

await E2eGrid.shortcut(tester, LogicalKeyboardKey.keyS, ctrl: true);
await _frames(tester);
expect(find.text('Confirm Data Changes'), findsOneWidget);
expect(find.text('TRANSACTION SCRIPT'), findsOneWidget);
expect(delegate.appliedPlans, isEmpty, reason: 'nothing before confirm');

await tester.tap(find.text('Apply Changes'));
await _frames(tester);
await tester.pump(const Duration(seconds: 6)); // toast timer

expect(delegate.appliedPlans, hasLength(1));
final sql = delegate.appliedPlans.single.statements.map((s) => s.sql);
expect(sql.where((s) => s.startsWith('UPDATE $table SET $column = ')),
hasLength(1));
expect(sql.where((s) => s.startsWith('INSERT INTO $table')), hasLength(1));
expect(sql.where((s) => s.startsWith('DELETE FROM $table')), hasLength(1));
expect(state.isDirty, isFalse);
});
}

testWidgets('Cancel in the preview keeps every pending edit',
timeout: _timeout, (tester) async {
final delegate = FakeTableDataDelegate();
final state = await pumpGenericTableView(tester, delegate);
await E2eGrid.shortcut(tester, LogicalKeyboardKey.keyE, ctrl: true);
await _frames(tester);
await E2eGrid.doubleTapCell(tester, 'Alice');
await E2eGrid.typeAndCommit(tester, 'Alicia');
await _frames(tester);

await E2eGrid.shortcut(tester, LogicalKeyboardKey.keyS, ctrl: true);
await _frames(tester);
await tester.tap(find.text('Cancel'));
await _frames(tester);
await tester.pump(const Duration(seconds: 6));

expect(delegate.appliedPlans, isEmpty);
E2eGrid.expectStaged(state.stagingBuffer!, modifiedCells: 1);
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import 'package:flutter/material.dart' as material;
import 'package:flutter_test/flutter_test.dart';
import 'package:querya_desktop/features/workspace/data_grid_filter_bar.dart';

import '../../support/fake_table_data_delegate.dart';
import '../../support/generic_table_view_harness.dart';
import '../helpers/e2e_grid_interactions.dart';

const _timeout = Timeout(Duration(seconds: 60));

FakeTableDataDelegate _accounts() => FakeTableDataDelegate(
columns: const ['id', 'name', 'balance'],
rows: const [
['1', 'alice', '150.00'],
['2', 'bob', '50.00'],
['3', 'charlie', '300.00'],
['4', 'david', '0.00'],
],
);

Future<void> _filter(WidgetTester tester, String text) async {
await tester.enterText(
find.descendant(
of: find.byType(DataGridFilterBar),
matching: find.byType(material.TextField),
),
text,
);
await tester.pump(const Duration(milliseconds: 400));
await tester.pumpAndSettle();
}

void main() {
testWidgets('balance > 100 keeps only the matching rows', timeout: _timeout,
(tester) async {
await pumpGenericTableView(tester, _accounts());
await tester.tap(find.byTooltip('Toggle Quick Filter'));
await tester.pumpAndSettle();

await _filter(tester, 'balance > 100');

expect(find.text('alice'), findsOneWidget);
expect(find.text('charlie'), findsOneWidget);
expect(find.text('bob'), findsNothing);
expect(find.text('david'), findsNothing);
expect(find.text('2 / 4'), findsOneWidget);

await _filter(tester, '');
expect(find.text('bob'), findsOneWidget);
expect(find.text('david'), findsOneWidget);
});

testWidgets('a plain word filters by any cell',
timeout: _timeout, (tester) async {
await pumpGenericTableView(tester, _accounts());
await tester.tap(find.byTooltip('Toggle Quick Filter'));
await tester.pumpAndSettle();

await _filter(tester, 'bob');
expect(find.text('alice'), findsNothing);
expect(find.text('charlie'), findsNothing);
expect(find.text('1 / 4'), findsOneWidget);
});

testWidgets('selecting a numeric cell shows its Quick Calc statistics',
timeout: _timeout, (tester) async {
await pumpGenericTableView(tester, _accounts());

await E2eGrid.tapCell(tester, '300.00');
await tester.pump(const Duration(milliseconds: 500));
await tester.pumpAndSettle();

expect(find.text('Count: '), findsOneWidget);
expect(find.text('Sum: '), findsOneWidget);
expect(find.text('Max: '), findsOneWidget);
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

import '../../support/fake_table_data_delegate.dart';
import '../../support/generic_table_view_harness.dart';
import '../helpers/e2e_grid_interactions.dart';

const _timeout = Timeout(Duration(seconds: 60));

void main() {
testWidgets('double click edits a cell, Revert All restores it',
timeout: _timeout, (tester) async {
final state = await pumpGenericTableView(tester, FakeTableDataDelegate());

await E2eGrid.shortcut(tester, LogicalKeyboardKey.keyE, ctrl: true);
await tester.pumpAndSettle();
expect(state.editMode, isTrue);
expect(find.text('No changes'), findsOneWidget);

await E2eGrid.doubleTapCell(tester, 'Bob');
await E2eGrid.typeAndCommit(tester, 'Bobby');
await tester.pumpAndSettle();

E2eGrid.expectStaged(state.stagingBuffer!, modifiedCells: 1);
expect(find.text('Bobby'), findsOneWidget);
expect(find.text('No changes'), findsNothing);

await tester.tap(find.text('Revert All'));
await tester.pumpAndSettle();

E2eGrid.expectStaged(state.stagingBuffer!);
expect(find.text('Bob'), findsOneWidget);
expect(find.text('Bobby'), findsNothing);
expect(find.text('No changes'), findsOneWidget);
});

testWidgets('Delete Row marks the selected row and Restore Row undoes it',
timeout: _timeout, (tester) async {
final state = await pumpGenericTableView(tester, FakeTableDataDelegate());
await E2eGrid.shortcut(tester, LogicalKeyboardKey.keyE, ctrl: true);
await tester.pumpAndSettle();

await E2eGrid.tapCell(tester, 'Carol');
await tester.tap(find.text('Delete Row'));
await tester.pumpAndSettle();
E2eGrid.expectStaged(state.stagingBuffer!, deleted: 1);
expect(find.text('Restore Row'), findsOneWidget);

await tester.tap(find.text('Restore Row'));
await tester.pumpAndSettle();
E2eGrid.expectStaged(state.stagingBuffer!);
expect(find.text('Delete Row'), findsOneWidget);
});

testWidgets('Add Row stages an insert and Revert All drops it',
timeout: _timeout, (tester) async {
final state = await pumpGenericTableView(tester, FakeTableDataDelegate());
await E2eGrid.shortcut(tester, LogicalKeyboardKey.keyE, ctrl: true);
await tester.pumpAndSettle();

await tester.tap(find.text('Add Row'));
await tester.pumpAndSettle();
E2eGrid.expectStaged(state.stagingBuffer!, inserted: 1);

await tester.tap(find.text('Revert All'));
await tester.pumpAndSettle();
E2eGrid.expectStaged(state.stagingBuffer!);
});

testWidgets('a read-only session never offers editing', timeout: _timeout,
(tester) async {
final state = await pumpGenericTableView(
tester,
FakeTableDataDelegate(),
isReadOnly: true,
);

await E2eGrid.shortcut(tester, LogicalKeyboardKey.keyE, ctrl: true);
await tester.pumpAndSettle();

expect(state.editMode, isFalse);
expect(find.text('Add Row'), findsNothing);
});
}
Loading