The issue in this question keeps coming up: somehow, states being set by some test methods are somehow carrying over to other tests.
I am coding in Google Apps Script, and unit-testing using QUnit for Google Apps Script.
The functions under test
/**
* Creates menu with driver items
**/
function createDriverMenu() {
SpreadsheetApp.getUi()
.createMenu("New Project Analysis")
.addItem("From File", "openFilePrompt")
.addToUi()
}
/**
* Sets formatting on the Sheet
* #param { Sheet } sheet
* #returns { Sheet } sheet
**/
function setFormattingFor(sheet) {
if (!sheet) throw Error("sheet required to setFormattingFor !")
// set conditional formatting on the range C2:C
var range = sheet.getRange("C2:C")
var rules = sheet.getConditionalFormatRules()
// if a cell's text equals FALSE, set that cell to white text, and the background to red
Logger.log(SpreadsheetApp)
ruleForFalseText = SpreadsheetApp.newConditionalFormatRule()
.setRanges([range])
.whenTextEqualTo("FALSE")
.setBackground("red")
.setFontColor("white")
.build()
rules.push(ruleForFalseText)
ruleForTrueText = SpreadsheetApp.newConditionalFormatRule()
.setRanges([range])
.whenTextEqualTo("TRUE")
.setBackground("green")
.setFontColor("white")
.build()
rules.push(ruleForTrueText)
ruleForInProgressText = SpreadsheetApp.newConditionalFormatRule()
.setRanges([range])
.whenTextEqualTo("IN PROGRESS")
.setBackground("orange")
.setFontColor("white")
.build()
rules.push(ruleForInProgressText)
ruleForPartialText = SpreadsheetApp.newConditionalFormatRule()
.setRanges([range])
.whenTextEqualTo("PARTIAL")
.setBackground("yellow")
.setFontColor("black")
.build()
rules.push(ruleForPartialText)
ruleForClosedTilTestableText = SpreadsheetApp.newConditionalFormatRule()
.setRanges([range])
.whenTextEqualTo("CLOSED TIL TESTABLE")
.setBackground("black")
.setFontColor("white")
.build()
rules.push(ruleForClosedTilTestableText)
sheet.setConditionalFormatRules(rules)
}
The tests
function testCreateDriverMenu() {
var menuStub // the stub for the menu
var savedSpreadsheetApp // the state of SpreadsheetApp from Google's Sheets API
QUnit.testStart(function() {
// create a menu stub
menuStub = {
addItemCalls : [],
addItem : function(txt, funcName) {
this.addItemCalls.push({ args : { displayTxt : txt, funcName: funcName } })
return this
},
addToUiCalled : false,
addToUi : function() { this.addToUiCalled = true }
}
// save the state of SpreadsheetApp to temporary variable
savedSpreadsheetApp = SpreadsheetApp;
SpreadsheetApp = {
ui : {
createMenuCalls : [],
createMenu : function(str) {
this.createMenuCalls.push({ args: str })
return menuStub
}
},
getUi : function() { return this.ui }
}
})
QUnit.test("testing createDriverMenu",
function() {
// hit the method under test
createDriverMenu({})
// do assertions
ok(SpreadsheetApp.ui.createMenuCalls.length, "SpreadsheetApp.getUi().createMenu was invoked at least once");
ok(menuStub.addItemCalls.length, "SpreadsheetApp.getUi().createMenu().addItem was invoked at least once");
ok(menuStub.addToUiCalled, "menu added to ui")
})
QUnit.testDone(function() {
// set SpreadsheetApp back
SpreadsheetApp = savedSpreadsheetApp;
})
}
function testSetFormattingFor() {
var sheet
var savedSpreadsheetApp
var rule
QUnit.testStart(function() {
savedSpreadsheetApp = SpreadsheetApp
rule = {
setRangesCalls : [],
setRanges: function(arr) {
this.setRangesCalls.push({ args: arr })
return this
},
whenEqualToCalls : [],
whenEqualTo : function(str) {
this.whenEqualToCalls.push({ args: str })
return this
},
setBackgroundCalls : [],
setBackground : function(str) {
this.setBackgroundCalls.push({ args: str })
return this
},
setFontColorCalls : [],
setFontColor : function(str) {
this.setFontColorCalls.push({ args: str })
return this
},
buildCalls : [],
build : function() {
this.buildCalls.push({ args: null })
return this
}
}
SpreadsheetApp = {
newConditionalFormatRuleCalls : [],
newConditionalFormatRule : function() {
this.newConditionalFormatRuleCalls.push({ args : null })
return rule
}
}
sheet = {
rule : [],
setConditionalFormatRulesCalls : [],
setConditionalFormatRules : function(rules) {
this.setConditionalFormatRulesCalls.push({ args: rules })
},
getConditionalFormatRulesCalls : [],
getConditionalFormatRules : function() {
return this.rules
},
range: [],
getRangeCalls: [],
getRange: function(str) {
this.getRangeCalls.push({ args : str })
return this.range;
}
}
})
QUnit.test("test setFormattingFor",
function() {
val = setFormattingFor(sheet)
// sheet.getRange should have been called
ok(sheet.getRangeCalls.length, "sheet.getRange was called at least once")
equal(val, sheet, "setFormattingFor returned something")
})
QUnit.test("test setFormattingFor with no args",
function() {
throws(function() {
setFormattingFor()
})
})
QUnit.testDone(function() {
SpreadsheetApp = savedSpreadsheetApp
})
}
Result
In introducing the second tests, both tests now fail:
Full text:
Died on test #1 at qunit.js (QUnit):1494 (sourceFromStacktrace) at qunit.js (QUnit):461 at gas-qunit (QUnit):191 (test) at tests:54 (testCreateDriverMenu) at tests:6 (tests) at gas-qunit (QUnit):56 (load) at Code:11 (doGet) : Cannot find function getUi in object [object Object].
Source:
at Code:47 (createDriverMenu) at tests:58 at qunit.js (QUnit):213 at qunit.js (QUnit):399 at qunit.js (QUnit):1542 (process) at qunit.js (QUnit):528 at qunit.js (QUnit):1294 at gas-qunit (QUnit):57 (load) at Code:11 (doGet)
Full text:
Died on test #1 at qunit.js (QUnit):1494 (sourceFromStacktrace) at qunit.js (QUnit):461 at gas-qunit (QUnit):191 (test) at tests:592 (testSetFormattingFor) at tests:15 (tests) at gas-qunit (QUnit):56 (load) at Code:11 (doGet) : Cannot find function whenTextEqualTo in object [object Object].
Source:
at Code:173 (setFormattingFor) at tests:594 at qunit.js (QUnit):213 at qunit.js (QUnit):399 at qunit.js (QUnit):1542 (process) at qunit.js (QUnit):528 at qunit.js (QUnit):1294 at gas-qunit (QUnit):57 (load) at Code:11 (doGet)
If I were to remove the new test, I simply get all tests passing.
Why is state pollution occurring in QUnit, even though I set the global objects to their stubs in the test setups, and revert the states back in the test teardowns?
Related
how i can call the onGridReady function to run unit test on the statement inside the function. My code base look something like below:
GridComponent.ts
export class GridComponent impletes Oninit{
constructor(serviceObj: ServiceClass) {
this.summaryData = {};
this.gridApi =
this.gridOptions = {
columnDef: [
{field: 'name', headerName: 'Name'},
{fiedld: 'dob', headerName: "Date of Birth"},
{fiedld: 'title', headerName: "Title"},
{fiedld: 'salary', headerName: "Salary"},
]
}
}
ngOnInit():void {
}
onGridReady(params: any) {
this.gridApi = params.api;
this.serviceObj.getDetails().subscribe((data: ModalClass[]) => {
if(data.length > 0) {
this.summaryData = data;
} else {
this.snackBar.open('No Records found.', dismiss);
}
},
(error: any) => {
this.snackBar.open('Error Occured', 'Dismiss');
}
)
}
}
GridComponent.html
<ag-grid-angular
style="width:100%;height:calc(82VH)
class="ag-theme-material"
[animateRows]="true"
[rowData] = "summaryData"
[gridOptions] = 'gridOptions'
></ag-grid-angular>
ServiceClass.ts
export ServiceClass {
public getDetails():any {
return this.http.get<ModalClass[]>(url, {withCredentials: true})
}
}
i have already wrote the test cases for ServiceClass.ts but not able to write the test cases for the statements and branches written inside onGridReady function. Please help.
Thanks in advance.
Try this:
it('test with data', () => {
// declarations
const mockData = [{id: 1}]
spyOn(service, 'getDetails').and.returnValue(of(mockData))
const spySnackBar = spyOn(component.snackBar, 'open')
const params = { api: 'mock' };
// call
component.onGridReady(params)
// expects
expect(component.summaryData).toEqual(mockData)
expect(component.gridApi).toEqual(params.api)
expect(spySnackBar).not.toHaveBeenCalled()
})
it('test without data', () => {
// declarations
const mockData = []
spyOn(service, 'getDetails').and.returnValue(of(mockData))
const spySnackBar = spyOn(component.snackBar, 'open')
const params = { api: 'mock' };
// call
component.onGridReady(params)
// expects
expect(component.summaryData).not.toEqual(mockData)
expect(component.gridApi).toEqual(params.api)
expect(spySnackBar).toHaveBeenCalled()
})
I have a file that exports some functions:
function getNow() {
console.log('real now');
return dayjs();
}
function groupProducts(productInfos, now) {
console.log('real group');
return productInfos.reduce((groups, productInfo) => {
const groupKey = dayjs(productInfo.saleStartDate) > now ? dayjs(productInfo.saleStartDate).format('YYYY-MM-DD') : dayjs(now).format('YYYY-MM-DD');
let group = groups[groupKey];
if (!group) {
group = [];
// eslint-disable-next-line no-param-reassign
groups[groupKey] = group;
}
group.push(productInfo.itemId);
return groups;
}, {});
}
async function fetchProducts(client, productInfos, now) {
const products = [];
const groups = groupProducts(productInfos, now);
for (const [date, ids] of Object.entries(productQueryGroups)) {
// eslint-disable-next-line no-await-in-loop
const productBatch = await fetchResources(
client.queryProducts,
{
articleIds: ids,
timestamp: date,
},
);
products.push(...productBatch);
}
return products;
}
module.exports = {
test: {
getNow,
groupProducts,
fetchProducts,
},
};
I run my tests with:
package.json script
"testw": "npx ../node_modules/.bin/jest --watch",
cli command:
npm run testw -- filename
In this test I exercise groupProducts and mock getNow. The real getNow is never called and the test passes.
describe('groupProducts', () => {
it('groups productInfo ids into today or future date groups', () => {
// Arrange
const nowSpy = jest.spyOn(test, 'getNow').mockReturnValue(dayjs('2001-02-03T04:05:06.007Z'));
const expectedMap = {
'2001-02-03': ['Art-Past', 'Art-Today'],
'2002-12-31': ['Art-Future-1', 'Art-Future-2'],
'2003-12-31': ['Art-Other-Future'],
};
const productInfos = [{
itemId: 'Art-Past',
saleStartDate: '1999-01-01',
}, {
itemId: 'Art-Today',
saleStartDate: '2001-02-03',
}, {
itemId: 'Art-Future-1',
saleStartDate: '2002-12-31',
}, {
itemId: 'Art-Future-2',
saleStartDate: '2002-12-31',
}, {
itemId: 'Art-Other-Future',
saleStartDate: '2003-12-31',
}];
// Assert
const dateToIds = test.groupProductInfosByTodayOrFutureDate(productInfos, test.getNow());
// Expect
expect(dateToIds).toEqual(expectedMap);
// Restore
nowSpy.mockRestore();
});
});
In this test I exercise fetchProducts and mock groupProducts. The real groupProducts is called and the causes the test to fail.
describe('fetchProducts', () => {
it.only('calls fetchResources with the timestamp and date for every product query group', async () => {
// Arrange
const productQueryGroups = {
[test.PRICE_GROUPS.CURRENT]: ['Art-Past', 'Art-Today'],
[test.PRICE_GROUPS.FUTURE]: ['Art-Future-1', 'Art-Future-2', 'Art-Other-Future'],
};
const groupProductsSpy = jest.spyOn(test, 'groupProducts').mockReturnValue( productQueryGroups);
const fetchResourcesSpy = jest.spyOn(test, 'fetchResources').mockResolvedValue([]);
// Act
await test.fetchProducts();
// Expect
expect(test.fetchResources).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({ articleIds: [productQueryGroups[test.PRICE_GROUPS.CURRENT]], timestamp: test.PRICE_GROUPS.CURRENT }));
// Restore
groupProductsSpy.mockRestore();
fetchResourcesSpy.mockRestore();
});
});
Error message
98 | function groupProducts(productInfos, now) {
> 99 | return productInfos.reduce((groups, productInfo) => {
| ^
100 | const groupKey = dayjs(productInfo.saleStartDate) > now ? dayjs(productInfo.saleStartDate).format('YYYY-MM-DD') : dayjs(now).format('YYYY-MM-DD');
101 |
102 | let group = groups[groupKey];
Why is the real groupProducts called? To me it looks completely analogous to the previous example.
I have a futurebuilder that builds the UI based on a List, it does the job, however I get duplicates due to the UI being built again and again whenever I navigate. My question is, is there a innate method in Dart that can remove duplicates from a list? I've tried this StackOverflow question however it doesn't work.
Here is my custom model:
class HomeList {
Widget navigateScreen;
String imagePath;
PatientInfo patientInfo;
HomeList({
this.navigateScreen,
this.imagePath = '',
this.patientInfo,
});
static List<HomeList> homeList = [];
}
Here is my function for the futureBuilder i'm getting the data from my cloud_firestore:
_getPatients() async {
if (didLoadpatients == 0) {
print('this is didloadpatients at start of func $didLoadpatients');
var document = await db
.collection('users')
.document(mUser.uid)
.collection('patients');
document.getDocuments().then((QuerySnapshot query) async {
query.documents.forEach((f) {
uids.add(f.data['uID']);
});
didLoadpatients++;
print('this is didloadpatients at end of func $didLoadpatients');
for (var i = 0; i < uids.length; i++) {
var userDocuments = await db.collection('users').document(uids[i]);
userDocuments.get().then((DocumentSnapshot doc) {
print(doc.data);
homeList.add(HomeList(
imagePath: 'assets/fitness_app/fitness_app.png',
patientInfo: new PatientInfo.fromFbase(doc.data)));
});
print(homeList);
}
});
} else
print('I am leaving the get patient function');
}
Future<bool> getData() async {
_getCurrentUser();
await Future.delayed(const Duration(milliseconds: 1500), () async {
_getPatients();
});
return true;
}
Any help would be appreciated thank you!
To remove duplicates you can use Set Data Structure instead of List.
Just use Set instead of List to get unique values only.
Before Adding you can Remove Element from model this will Work
dummymodel.removeWhere((m) => m.id == id);
dummymodel.add(dummymodel.fromJson(data));
To Remove Duplicates from Data Model simply use Set (Data structure),
Original List with Duplicate Entries:
List<MyDataModel> mList = [MyDataModel(1), MyDataModel(2), MyDataModel(1), MyDataModel(3)];
New List that removes duplicate Entries from your List<MyDataModel>:
List<MyDataModel> mNewList = list.toSet().toList();
Output:
The result will be like
MyDataModel(1), MyDataModel(2), MyDataModel(3)
To remove the duplicate elements from custom object list, you need to override == and hashcode methods in your POJO class and then add the items in Set and again convert set to list to remove duplicate objects. Below is the working code:-
class TrackPointList {
double latitude;
double longitude;
String eventName;
Time timeZone;
TrackPointList({
this.latitude,
this.longitude,
this.eventName,
this.timeZone,
});
#override
bool operator==(other) {
// Dart ensures that operator== isn't called with null
// if(other == null) {
// return false;
// }
if(other is! TrackPointList) {
return false;
}
// ignore: test_types_in_equals
return eventName == (other as TrackPointList).eventName;
}
int _hashCode;
#override
int get hashCode {
if(_hashCode == null) {
_hashCode = eventName.hashCode;
}
return _hashCode;
}
factory TrackPointList.fromJson(Map<String, dynamic> json) => TrackPointList(
latitude: json["latitude"].toDouble(),
longitude: json["longitude"].toDouble(),
eventName: json["eventName"],
timeZone: timeValues.map[json["timeZone"]],
);
Map<String, dynamic> toJson() => {
"latitude": latitude,
"longitude": longitude,
"eventName": eventName,
"timeZone": timeValues.reverse[timeZone],
};
}
Above is the POJO class. Now below is the method which helps you to filter the objects according to the eventName data member.
List<TrackPointList> getFilteredList(List<TrackPointList> list){
final existing = Set<TrackPointList>();
final unique = list
.where((trackingPoint) => existing.add(trackingPoint))
.toList();
return unique;
}
This will work definitely.
Please +1 if it helps you.
I've come up with quite a brute force solution. Instead of
_getPatients() async {
if (didLoadpatients == 0) {
print('this is didloadpatients at start of func $didLoadpatients');
var document = await db
.collection('users')
.document(mUser.uid)
.collection('patients');
document.getDocuments().then((QuerySnapshot query) async {
query.documents.forEach((f) {
uids.add(f.data['uID']);
});
didLoadpatients++;
print('this is didloadpatients at end of func $didLoadpatients');
for (var i = 0; i < uids.length; i++) {
var userDocuments = await db.collection('users').document(uids[i]);
userDocuments.get().then((DocumentSnapshot doc) {
print(doc.data);
homeList.add(HomeList(
imagePath: 'assets/fitness_app/fitness_app.png',
patientInfo: new PatientInfo.fromFbase(doc.data)));
});
print(homeList);
}
});
} else
print('I am leaving the get patient function');
}
I've done what #Jay Mungara says and clear my Set everytime my UI rebuilds:
_getPatients() async {
homeList.clear();
if (didLoadpatients == 0) {
print('this is didloadpatients at start of func $didLoadpatients');
var document = await db
.collection('users')
.document(mUser.uid)
.collection('patients');
document.getDocuments().then((QuerySnapshot query) async {
query.documents.forEach((f) {
uids.add(f.data['uID']);
});
didLoadpatients++;
print('this is didloadpatients at end of func $didLoadpatients');
for (var i = 0; i < uids.length; i++) {
var userDocuments = await db.collection('users').document(uids[i]);
userDocuments.get().then((DocumentSnapshot doc) {
print(doc.data);
homeList.add(HomeList(
imagePath: 'assets/fitness_app/fitness_app.png',
patientInfo: new PatientInfo.fromFbase(doc.data)));
});
print(homeList);
}
});
} else
print('I am leaving the get patient function');
}
Thank you for all your answers!
this is a small examples to remove duplicate element
removeDuplicate() {
List<dynamic> demoList = [
{"userId": 1, "id": 1, "name": "thappu1"},
{"userId": 2, "id": 2, "name": "appu"},
{"userId": 1, "id": 1, "name": "thappu1"},
{"userId": 2, "id": 2, "name": "appu"},
{"userId": 2, "id": 2, "name": "appu"},
{"userId": 2, "id": 2, "name": "appu"},
{"userId": 2, "id": 2, "name": "appu"},
];
var toRemove = {};
demoList.forEach((e) {
toRemove.putIfAbsent("$e", () => e);
});
print(toRemove.keys.toList());
}
output is
[{userId: 1, id: 1, name: thappu1}, {userId: 2, id: 2, name: appu}]
I'm trying to compare faces with AWS rekognition API. but somehow I'm getting "broken pipe" error all the time. There is no problem on aws keys and photos. I'm trying to get more info from http.post but It just says "broken pipe", it doesn't give any detail, unfortunately.
Scenario;
User takes 2 photos (working)
on second taken, I will parse images to bytes (working)
send bytes with standard request to aws API (doesn't work)
I changed the image quality to the lowest as well, but It didn't help.
Main.dart code
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'testa.dart';
import 'package:path_provider/path_provider.dart';
List<CameraDescription> cameras;
Future<void> main() async {
cameras = await availableCameras();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
CameraController controller;
#override
void initState() {
super.initState();
controller = CameraController(cameras[0], ResolutionPreset.low);
controller.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
}
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
Future<String> _checkImage(String filePath, String secondPath) async {
File sourceImagefile, targetImagefile; //load source and target images in those File objects
String accessKey, secretKey, region ; //load your aws account info in those variables
print(filePath);
print(secondPath);
targetImagefile = File(filePath);
sourceImagefile = File(secondPath);
print(targetImagefile.existsSync());
print(sourceImagefile.existsSync());
accessKey = '';
secretKey = '';
region = 'eu-west-1';
RekognitionHandler rekognition = new RekognitionHandler(accessKey, secretKey, region);
String labelsArray = await rekognition.compareFaces(sourceImagefile, targetImagefile);
return labelsArray;
}
Widget cameraPart() {
if (!controller.value.isInitialized) {
return Container();
}
return AspectRatio(
aspectRatio:
controller.value.aspectRatio,
child: CameraPreview(controller));
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: cameraPart(),
floatingActionButton: FloatingActionButton(
onPressed: takePhoto,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
Future<String> get360PhotoFolder() async {
final Directory appFolder = await getAppFolder();
final String dirPath = '${appFolder.path}/photos360';
await Directory(dirPath).create(recursive: true);
return dirPath;
}
String firstPath = '';
String secondPath = '';
Future<bool> takePhoto() async {
final String dirPath = await get360PhotoFolder();
final String filePath = '$dirPath/${timestamp()}_test.jpg';
try {
debugPrint('photo taken - $filePath');
await controller.takePicture(filePath);
setState(() {
if (firstPath == '') {
print('a');
firstPath = filePath;
}else if (secondPath == '') {
print('b');
secondPath = filePath;
_checkImage(firstPath, secondPath).then((value) {
print(value);
}).catchError((error) {
print(error);
});
firstPath = '';
secondPath = '';
}
});
} on CameraException catch (e) {
print([e.code, e.description]);
return true;
}
return false;
}
String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();
Future<Directory> getAppFolder() async =>
await getApplicationDocumentsDirectory();
}
AWS rekognition code
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:intl/intl.dart';
import 'testb.dart';
class RekognitionHandler {
final String _accessKey, _secretKey, _region;
RekognitionHandler(this._accessKey, this._secretKey, this._region);
Future<String> _rekognitionHttp(String amzTarget, String body) async {
String endpoint = "https://rekognition.$_region.amazonaws.com/";
String host = "rekognition.$_region.amazonaws.com";
String httpMethod = "POST";
String service = "rekognition";
var now = new DateTime.now().toUtc();
var amzFormatter = new DateFormat("yyyyMMdd'T'HHmmss'Z'");
String amzDate =
amzFormatter.format(now); // format should be '20170104T233405Z"
var dateFormatter = new DateFormat('yyyyMMdd');
String dateStamp = dateFormatter.format(
now); // Date w/o time, used in credential scope. format should be "20170104"
int bodyLength = body.length;
String queryStringParamters = "";
Map<String, String> headerParamters = {
"content-length": bodyLength.toString(),
"content-type": "application/x-amz-json-1.1",
"host": host,
"x-amz-date": amzDate,
"x-amz-target": amzTarget
};
String signature = Signature.generateSignature(
endpoint,
service,
_region,
_secretKey,
httpMethod,
now,
queryStringParamters,
headerParamters,
body);
String authorization =
"AWS4-HMAC-SHA256 Credential=$_accessKey/$dateStamp/$_region/$service/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date;x-amz-target, Signature=$signature";
headerParamters.putIfAbsent('Authorization', () => authorization);
//String labelsArray = "";
StringBuffer builder = new StringBuffer();
try {
HttpClient httpClient = new HttpClient();
httpClient.connectionTimeout = Duration(minutes: 10);
HttpClientRequest request = await httpClient.postUrl(Uri.parse(endpoint));
request.headers.set('content-length', headerParamters['content-length']);
request.headers.set('content-type', headerParamters['content-type']);
request.headers.set('host', headerParamters['host']);
request.headers.set('x-amz-date', headerParamters['x-amz-date']);
request.headers.set('x-amz-target', headerParamters['x-amz-target']);
request.headers.set('Authorization', headerParamters['Authorization']);
request.write(body);
HttpClientResponse response = await request.close();
await for (String a in response.transform(utf8.decoder)) {
builder.write(a);
}
} catch (e) {
print(e);
}
return Future.value(builder.toString());
}
Future<String> compareFaces(
File sourceImagefile, File targetImagefile) async {
try {
List<int> sourceImageBytes = sourceImagefile.readAsBytesSync();
String base64SourceImage = base64Encode(sourceImageBytes);
List<int> targetImageBytes = targetImagefile.readAsBytesSync();
String base64TargetImage = base64Encode(targetImageBytes);
String body =
'{"SourceImage":{"Bytes": "$base64SourceImage"},"TargetImage":{"Bytes": "$base64TargetImage"}}';
String amzTarget = "RekognitionService.CompareFaces";
String response = await _rekognitionHttp(amzTarget, body);
return response;
} catch (e) {
print(e);
return "{}";
}
}
}
I wrote a method which returns true if there are folders left in the modal to be added and return false if there are no folders left in the modal to be added to the application
my method in angular/typesrcipt
ifAllFoldersHaveBeenAdded() {
let added = false;
let folderToExclude = find(this.bdDataModel.lenderDefinedFolders, {
name: 'Correspondence' });
let foldersToBeChecked = without(this.bdDataModel.lenderDefinedFolders, folderToExclude);
for (let i = 0; i < foldersToBeChecked.length; i++) {
let folderPresent = find(this.bdDataModel.folders, { name: foldersToBeChecked[i].name });
if (folderPresent) {
added = true;
} else {
added = false;
return added;
}
}
return added;
}
my test...
describe('ifAllFoldersHaveBeenAdded()', () => {
it('returns false if there are folders left in the modal to be added', () => {
let added = false;
$ctrl.bdDataModel.folders;
$ctrl.foldersToBeChecked = [{ name: 'FMS' }, { name: 'Other' }];
$ctrl.folderPresent = { name: 'FMS' };
$ctrl.ifAllFoldersHaveBeenAdded();
added = true;
expect(added).toEqual(true);
});
it('returns true is all folders have been added to the application', () => {
let added = false;
$ctrl.bdDataModel.folders;
$ctrl.foldersToBeChecked = [{ name: 'FMS' }, { name: 'Other' }];
$ctrl.folderPresent = { name: 'LMI' };
$ctrl.ifAllFoldersHaveBeenAdded();
expect(added).toEqual(false);
});
});
Both tests pass but icov coverage report is marking the following lines as uncovered...
find(this.bdDataModel.folders, { name: foldersToBeChecked[i].name });
if (folderPresent) {
added = true;
}
else {
added = false;
return added;
}
please tell what i should add in the test to have a 100% test coverage for this unit test.
thanks in advance
There is so much wrong with your test. First off, you need to get rid of the local added variables completely. Doing something like the following
added = true;
expect(added).toEqual(true);
Is essentially the same as doing expect(true).toBe(true)
Next, the folderPresent and foldersToBeChecked variables are local to the ifAllFoldersHaveBeenAdded function. They are not controller variables. You don't need to set $ctrl.folderPresent or $ctrl.foldersToBeChecked in your test.
You need to define these two variables $ctrl.bdDataModel.lenderDefinedFolders and $ctrl.bdDataModel.folders
Because lenderDefinedFolders is undefined the length of foldersToBeChecked in your function is going to be 0. So the for loop will never execute.
Your test should look something like this:
it('returns false if there are folders left in the modal to be added', () => {
$ctrl.bdDataModel.lenderDefinedFolders = [{ //add lender defined folders here }]
$ctrl.bdDataModel.folders = [{ //add some folders here}]
let added = $ctrl.ifAllFoldersHaveBeenAdded();
expect(added).toEqual(true);
});