Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41d2881c4a |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 195 KiB After Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 193 KiB |
@@ -14,8 +14,6 @@ class Profile {
|
|||||||
final String gid, fullName, role;
|
final String gid, fullName, role;
|
||||||
final String? employeeCode, departmentName, designationTitle, reportingManagerName;
|
final String? employeeCode, departmentName, designationTitle, reportingManagerName;
|
||||||
final bool isManager;
|
final bool isManager;
|
||||||
/// Org base currency (ISO 4217); null on older servers ⇒ INR.
|
|
||||||
final String? currency;
|
|
||||||
Profile.fromJson(Map<String, dynamic> j)
|
Profile.fromJson(Map<String, dynamic> j)
|
||||||
: gid = j['gid'] ?? '',
|
: gid = j['gid'] ?? '',
|
||||||
fullName = j['fullName'] ?? '',
|
fullName = j['fullName'] ?? '',
|
||||||
@@ -24,8 +22,7 @@ class Profile {
|
|||||||
departmentName = j['departmentName'],
|
departmentName = j['departmentName'],
|
||||||
designationTitle = j['designationTitle'],
|
designationTitle = j['designationTitle'],
|
||||||
reportingManagerName = j['reportingManagerName'],
|
reportingManagerName = j['reportingManagerName'],
|
||||||
isManager = j['isManager'] == true,
|
isManager = j['isManager'] == true;
|
||||||
currency = j['currency'] as String?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Today {
|
class Today {
|
||||||
@@ -84,16 +81,13 @@ class LeaveRequest {
|
|||||||
class Payslip {
|
class Payslip {
|
||||||
final String gid, periodMonth, status;
|
final String gid, periodMonth, status;
|
||||||
final num gross, totalDeductions, netPay;
|
final num gross, totalDeductions, netPay;
|
||||||
/// Org base currency (ISO 4217); null on older servers ⇒ INR.
|
|
||||||
final String? currency;
|
|
||||||
Payslip.fromJson(Map<String, dynamic> j)
|
Payslip.fromJson(Map<String, dynamic> j)
|
||||||
: gid = j['gid'] ?? '',
|
: gid = j['gid'] ?? '',
|
||||||
periodMonth = j['periodMonth'] ?? '',
|
periodMonth = j['periodMonth'] ?? '',
|
||||||
status = j['status'] ?? '',
|
status = j['status'] ?? '',
|
||||||
gross = j['gross'] ?? 0,
|
gross = j['gross'] ?? 0,
|
||||||
totalDeductions = j['totalDeductions'] ?? 0,
|
totalDeductions = j['totalDeductions'] ?? 0,
|
||||||
netPay = j['netPay'] ?? 0,
|
netPay = j['netPay'] ?? 0;
|
||||||
currency = j['currency'] as String?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TeamMember {
|
class TeamMember {
|
||||||
@@ -116,9 +110,6 @@ class ApiService {
|
|||||||
final Settings settings;
|
final Settings settings;
|
||||||
ApiService(this.settings);
|
ApiService(this.settings);
|
||||||
|
|
||||||
/// Org base currency from the last profile seen (login or /me/profile).
|
|
||||||
String? currency;
|
|
||||||
|
|
||||||
Uri _uri(String p, [Map<String, String>? q]) =>
|
Uri _uri(String p, [Map<String, String>? q]) =>
|
||||||
Uri.parse('${Settings.baseUrl}$p').replace(queryParameters: q);
|
Uri.parse('${Settings.baseUrl}$p').replace(queryParameters: q);
|
||||||
|
|
||||||
@@ -144,17 +135,12 @@ class ApiService {
|
|||||||
throw ApiException(_msg(body) ?? 'Invalid email or PIN', res.statusCode);
|
throw ApiException(_msg(body) ?? 'Invalid email or PIN', res.statusCode);
|
||||||
}
|
}
|
||||||
final p = Profile.fromJson(body['profile'] as Map<String, dynamic>);
|
final p = Profile.fromJson(body['profile'] as Map<String, dynamic>);
|
||||||
currency = p.currency ?? currency;
|
|
||||||
await settings.saveSession(token: body['accessToken'] as String, name: p.fullName, role: p.role);
|
await settings.saveSession(token: body['accessToken'] as String, name: p.fullName, role: p.role);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- me ----
|
// ---- me ----
|
||||||
Future<Profile> profile() async {
|
Future<Profile> profile() async => Profile.fromJson(await _get('/api/v1/me/profile'));
|
||||||
final p = Profile.fromJson(await _get('/api/v1/me/profile'));
|
|
||||||
currency = p.currency ?? currency;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
Future<Today> today() async => Today.fromJson(await _get('/api/v1/me/attendance/today'));
|
Future<Today> today() async => Today.fromJson(await _get('/api/v1/me/attendance/today'));
|
||||||
|
|
||||||
Future<void> checkIn({double? lat, double? lng, String? selfie}) =>
|
Future<void> checkIn({double? lat, double? lng, String? selfie}) =>
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
import 'package:intl/intl.dart';
|
|
||||||
|
|
||||||
/// Formats a payroll amount in the organisation's currency.
|
|
||||||
///
|
|
||||||
/// [currency] is the ISO 4217 code the server sends on payslips / profile
|
|
||||||
/// (`currency`). Missing or blank ⇒ INR, which keeps the original output:
|
|
||||||
/// rupee sign, Indian lakh grouping, no decimals (e.g. `₹1,23,457`).
|
|
||||||
/// Other currencies print the ISO code and the currency's own minor units
|
|
||||||
/// (e.g. `AED 12,345.50`, `BHD 1,234.500`).
|
|
||||||
String formatMoney(num v, [String? currency]) {
|
|
||||||
final code = (currency ?? '').trim().toUpperCase();
|
|
||||||
if (code.isEmpty || code == 'INR') {
|
|
||||||
return '₹${NumberFormat('#,##,###').format(v)}';
|
|
||||||
}
|
|
||||||
// NumberFormat.currency picks the ISO default fraction digits for `name`
|
|
||||||
// (BHD/KWD/OMR 3, JPY 0, most others 2).
|
|
||||||
return NumberFormat.currency(locale: 'en', name: code, symbol: '$code ').format(v);
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import '../api_service.dart';
|
import '../api_service.dart';
|
||||||
import '../money.dart';
|
|
||||||
import '../theme.dart';
|
import '../theme.dart';
|
||||||
|
|
||||||
class PayslipsScreen extends StatefulWidget {
|
class PayslipsScreen extends StatefulWidget {
|
||||||
@@ -41,8 +40,7 @@ class _PayslipsScreenState extends State<PayslipsScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Payslip currency, else the profile's, else INR (older servers).
|
String _inr(num v) => '₹${NumberFormat('#,##,###').format(v)}';
|
||||||
String _money(Payslip p, num v) => formatMoney(v, p.currency ?? widget.api.currency);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -64,7 +62,7 @@ class _PayslipsScreenState extends State<PayslipsScreen> {
|
|||||||
title: Text(_month(p.periodMonth), style: const TextStyle(fontWeight: FontWeight.w600)),
|
title: Text(_month(p.periodMonth), style: const TextStyle(fontWeight: FontWeight.w600)),
|
||||||
subtitle: const Text('Net pay'),
|
subtitle: const Text('Net pay'),
|
||||||
trailing: Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [
|
trailing: Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [
|
||||||
Text(_money(p, p.netPay), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: AppColors.emerald)),
|
Text(_inr(p.netPay), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: AppColors.emerald)),
|
||||||
Text(p.status, style: const TextStyle(fontSize: 11, color: AppColors.muted)),
|
Text(p.status, style: const TextStyle(fontSize: 11, color: AppColors.muted)),
|
||||||
]),
|
]),
|
||||||
onTap: () => showModalBottomSheet(
|
onTap: () => showModalBottomSheet(
|
||||||
@@ -74,10 +72,10 @@ class _PayslipsScreenState extends State<PayslipsScreen> {
|
|||||||
child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [
|
child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [
|
||||||
Text(_month(p.periodMonth), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: AppColors.navy)),
|
Text(_month(p.periodMonth), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: AppColors.navy)),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_row('Gross earnings', _money(p, p.gross)),
|
_row('Gross earnings', _inr(p.gross)),
|
||||||
_row('Total deductions', '− ${_money(p, p.totalDeductions)}'),
|
_row('Total deductions', '− ${_inr(p.totalDeductions)}'),
|
||||||
const Divider(height: 24),
|
const Divider(height: 24),
|
||||||
_row('Net pay', _money(p, p.netPay), bold: true),
|
_row('Net pay', _inr(p.netPay), bold: true),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
const Text('Full PDF payslip is available on the Scalar360 web portal.',
|
const Text('Full PDF payslip is available on the Scalar360 web portal.',
|
||||||
style: TextStyle(fontSize: 12, color: AppColors.muted)),
|
style: TextStyle(fontSize: 12, color: AppColors.muted)),
|
||||||
|
|||||||
@@ -33,14 +33,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.13.1"
|
version: "2.13.1"
|
||||||
boolean_selector:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: boolean_selector
|
|
||||||
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.2"
|
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -69,10 +61,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: clock
|
name: clock
|
||||||
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
|
sha256: e51d50bca3217c9a9fa2b41a30e4a38971133f5f9ec7a3d57bae095007f1d28e
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.1.3"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -113,14 +105,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.9"
|
version: "1.0.9"
|
||||||
fake_async:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: fake_async
|
|
||||||
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.3"
|
|
||||||
ffi:
|
ffi:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -214,11 +198,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.35"
|
version: "2.0.35"
|
||||||
flutter_test:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -384,30 +363,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.12.0"
|
version: "4.12.0"
|
||||||
leak_tracker:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: leak_tracker
|
|
||||||
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "11.0.2"
|
|
||||||
leak_tracker_flutter_testing:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: leak_tracker_flutter_testing
|
|
||||||
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.10"
|
|
||||||
leak_tracker_testing:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: leak_tracker_testing
|
|
||||||
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.2"
|
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -416,14 +371,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "4.0.0"
|
||||||
matcher:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: matcher
|
|
||||||
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.12.19"
|
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -581,22 +528,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.2"
|
version: "1.10.2"
|
||||||
stack_trace:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stack_trace
|
|
||||||
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.12.1"
|
|
||||||
stream_channel:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stream_channel
|
|
||||||
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.4"
|
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -613,14 +544,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.2"
|
version: "1.2.2"
|
||||||
test_api:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: test_api
|
|
||||||
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.7.11"
|
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -717,14 +640,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.0"
|
||||||
vm_service:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vm_service
|
|
||||||
sha256: "89b11d62e1040ee681af3b4f1c97a803ecbf010c6e8b9c5896ee5b08c3bf7b78"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "15.4.0"
|
|
||||||
web:
|
web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ dependencies:
|
|||||||
cupertino_icons: ^1.0.6
|
cupertino_icons: ^1.0.6
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
|
||||||
sdk: flutter
|
|
||||||
flutter_launcher_icons: ^0.14.0
|
flutter_launcher_icons: ^0.14.0
|
||||||
flutter_native_splash: ^2.4.0
|
flutter_native_splash: ^2.4.0
|
||||||
flutter_lints: ^4.0.0
|
flutter_lints: ^4.0.0
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:scalar_attendance/api_service.dart';
|
|
||||||
import 'package:scalar_attendance/money.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
// The formatter the payslips screen used before org currencies.
|
|
||||||
String legacyInr(num v) => '₹${NumberFormat('#,##,###').format(v)}';
|
|
||||||
|
|
||||||
group('formatMoney', () {
|
|
||||||
test('missing / INR currency is byte-identical to the old rupee output', () {
|
|
||||||
for (final v in [0, 7, 999, 1000, 54321, 123456.7, 1234567, 98765432.49]) {
|
|
||||||
expect(formatMoney(v), legacyInr(v));
|
|
||||||
expect(formatMoney(v, null), legacyInr(v));
|
|
||||||
expect(formatMoney(v, ''), legacyInr(v));
|
|
||||||
expect(formatMoney(v, 'INR'), legacyInr(v));
|
|
||||||
expect(formatMoney(v, 'inr'), legacyInr(v));
|
|
||||||
}
|
|
||||||
expect(formatMoney(1234567), '₹12,34,567');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('AED uses the ISO code, western grouping and 2 decimals', () {
|
|
||||||
expect(formatMoney(12345.5, 'AED'), 'AED 12,345.50');
|
|
||||||
expect(formatMoney(0, 'AED'), 'AED 0.00');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('BHD uses 3 decimals', () {
|
|
||||||
expect(formatMoney(1234.5, 'BHD'), 'BHD 1,234.500');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group('payslip / profile currency', () {
|
|
||||||
test('parsed when present, null on older servers', () {
|
|
||||||
final withCur = Payslip.fromJson({'gid': 'p1', 'netPay': 10, 'currency': 'AED'});
|
|
||||||
final without = Payslip.fromJson({'gid': 'p1', 'netPay': 10});
|
|
||||||
expect(withCur.currency, 'AED');
|
|
||||||
expect(without.currency, isNull);
|
|
||||||
expect(Profile.fromJson({'currency': 'SAR'}).currency, 'SAR');
|
|
||||||
expect(Profile.fromJson({}).currency, isNull);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// This is a basic Flutter widget test.
|
||||||
|
//
|
||||||
|
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||||
|
// utility in the flutter_test package. For example, you can send tap and scroll
|
||||||
|
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||||
|
// tree, read text, and verify that the values of widget properties are correct.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'package:scalar_attendance/main.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||||
|
// Build our app and trigger a frame.
|
||||||
|
await tester.pumpWidget(const MyApp());
|
||||||
|
|
||||||
|
// Verify that our counter starts at 0.
|
||||||
|
expect(find.text('0'), findsOneWidget);
|
||||||
|
expect(find.text('1'), findsNothing);
|
||||||
|
|
||||||
|
// Tap the '+' icon and trigger a frame.
|
||||||
|
await tester.tap(find.byIcon(Icons.add));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// Verify that our counter has incremented.
|
||||||
|
expect(find.text('0'), findsNothing);
|
||||||
|
expect(find.text('1'), findsOneWidget);
|
||||||
|
});
|
||||||
|
}
|
||||||