2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-06-14 11:15:26 +00:00

Stock location scan (#169)

* Add action for scanning a stock location into another location

* Adds barcode scan handler for new functionality

* Handle scanning of stock location

* Cleanup

* Refactor existing barcode scanning functions

- Will require extensive testing and validation

* Add entry to release notes

* Delete dead code

* Improved ordering based on stock quantity

* Bug fix for 'adjustStock' function

* Improve error responses for barcode scanning

* Improve error responses for barcode scanning

* Remove old debug statements

* Add some extra explanatory texts

* Icon change

* Fixes for unit tests

* Adds extra functionality for user profile manager

* Refactor barcode code - do not rely on BuildContext

* Adds initial unit testing for barcode scanning

- Work on mocking barcode data
- Add hooks for testing snackBar and audio files

* Linting fixes

* More barcode unit tests

* Cleanup unit tests for barcode

* Remove unused import

* Handle HTTPException in API

* Improvements for API unit testing

* Unit testing for scanning item into location

* Add unit test for scanning in items from a location context

* Unit test for scanning location into parent location

* Improve feedback for barcode scanning events
This commit is contained in:
Oliver
2022-07-18 22:10:00 +10:00
committed by GitHub
parent c6678e201f
commit aa274b2e45
21 changed files with 711 additions and 255 deletions

View File

@ -5,6 +5,7 @@
import "package:test/test.dart";
import "package:inventree/api.dart";
import "package:inventree/helpers.dart";
import "package:inventree/user_profile.dart";
@ -94,6 +95,9 @@ void main() {
assert(!api.checkConnection());
debugContains("Token request failed: STATUS 401");
debugContains("showSnackIcon: 'Not Connected'");
} else {
assert(false);
}
@ -137,6 +141,9 @@ void main() {
assert(api.checkPermission("stocklocation", "delete"));
assert(!api.checkPermission("part", "weirdpermission"));
assert(api.checkPermission("blah", "bloo"));
debugContains("Received token from server");
debugContains("showSnackIcon: 'Connected to Server'");
});
});

160
test/barcode_test.dart Normal file
View File

@ -0,0 +1,160 @@
/*
* Unit testing for barcode scanning functionality.
*
* As the unit testing framework cannot really "scan" barcode data,
* we will mock the scanned data by passing raw "barcode" data to the scanning framework.
*/
import "package:flutter_test/flutter_test.dart";
import "package:inventree/api.dart";
import "package:inventree/barcode.dart";
import "package:inventree/helpers.dart";
import "package:inventree/user_profile.dart";
import "package:inventree/inventree/stock.dart";
void main() {
// Connect to the server
setUpAll(() async {
final prf = await UserProfileDBManager().getProfileByName("Test Profile");
if (prf != null) {
UserProfileDBManager().deleteProfile(prf);
}
bool result = await UserProfileDBManager().addProfile(
UserProfile(
name: "Test Profile",
server: "http://localhost:12345",
username: "testuser",
password: "testpassword",
selected: true,
),
);
assert(result);
assert(await UserProfileDBManager().selectProfileByName("Test Profile"));
assert(await InvenTreeAPI().connectToServer());
});
setUp(() async {
// Clear the debug log
clearDebugMessage();
});
group("Test BarcodeScanHandler:", () {
// Tests for scanning a "generic" barcode
var handler = BarcodeScanHandler();
test("Empty Barcode", () async {
// Handle an 'empty' barcode
await handler.processBarcode(null, "");
debugContains("Scanned barcode data: ''");
debugContains("showSnackIcon: 'Barcode scan error'");
assert(debugMessageCount() == 2);
});
test("Junk Data", () async {
// test scanning 'junk' data
await handler.processBarcode(null, "abcdefg");
debugContains("Scanned barcode data: 'abcdefg'");
debugContains("showSnackIcon: 'No match for barcode'");
});
test("Invalid StockLocation", () async {
// Scan an invalid stock location
await handler.processBarcode(null, '{"stocklocation": 999999}');
debugContains("Scanned barcode data: '{\"stocklocation\": 999999}'");
debugContains("showSnackIcon: 'No match for barcode'");
assert(debugMessageCount() == 2);
});
});
group("Test StockItemScanIntoLocationHandler:", () {
// Tests for scanning a stock item into a location
test("Scan Into Location", () async {
final item = await InvenTreeStockItem().get(1) as InvenTreeStockItem?;
assert(item != null);
assert(item!.pk == 1);
var handler = StockItemScanIntoLocationHandler(item!);
await handler.processBarcode(null, '{"stocklocation": 7}');
// Check the location has been updated
await item.reload();
assert(item.locationId == 7);
debugContains("Scanned stock location 7");
// Scan into a new location
await handler.processBarcode(null, '{"stocklocation": 1}');
await item.reload();
assert(item.locationId == 1);
});
});
group("Test StockLocationScanInItemsHandler:", () {
// Tests for scanning items into a stock location
test("Scan In Items", () async {
final location = await InvenTreeStockLocation().get(1) as InvenTreeStockLocation?;
assert(location != null);
assert(location!.pk == 1);
var handler = StockLocationScanInItemsHandler(location!);
// Scan multiple items into this location
for (int id in [1, 2, 11]) {
await handler.processBarcode(null, '{"stockitem": ${id}}');
var item = await InvenTreeStockItem().get(id) as InvenTreeStockItem?;
assert(item != null);
assert(item!.pk == id);
assert(item!.locationId == 1);
}
});
});
group("Test ScanParentLocationHandler:", () {
// Tests for scanning a location into a parent location
test("Scan Parent", () async {
final location = await InvenTreeStockLocation().get(7) as InvenTreeStockLocation?;
assert(location != null);
assert(location!.pk == 7);
assert(location!.parentId == 4);
var handler = ScanParentLocationHandler(location!);
// Scan into new parent location
await handler.processBarcode(null, '{"stocklocation": 1}');
await location.reload();
assert(location.parentId == 1);
// Scan back into old parent location
await handler.processBarcode(null, '{"stocklocation": 4}');
await location.reload();
assert(location.parentId == 4);
debugContains("showSnackIcon: 'Scanned into location'");
});
});
}

View File

@ -2,11 +2,11 @@
* Unit tests for accessing various model classes via the API
*/
import "package:inventree/inventree/model.dart";
import "package:test/test.dart";
import "package:inventree/api.dart";
import "package:inventree/user_profile.dart";
import "package:inventree/inventree/model.dart";
import "package:inventree/inventree/part.dart";
@ -112,32 +112,40 @@ void main() {
assert(result != null);
assert(result is InvenTreePart);
APIResponse? response;
if (result != null) {
InvenTreePart part = result as InvenTreePart;
assert(part.name == "M2x4 LPHS");
// Change the name to something else
assert(await part.update(
response = await part.update(
values: {
"name": "Woogle",
}
));
);
assert(response.isValid());
assert(response.statusCode == 200);
assert(await part.reload());
assert(part.name == "Woogle");
// And change it back again
assert(await part.update(
response = await part.update(
values: {
"name": "M2x4 LPHS"
}
));
);
assert(response.isValid());
assert(response.statusCode == 200);
assert(await part.reload());
assert(part.name == "M2x4 LPHS");
}
});
});
}