Using Faker to get and set gender for all following data - node.js

I'm using Faker with TypeScript and am struggling to figure out how to capture the returned gender from Faker in a way that I can then use in subsequent calls. This is what I'd like to do:
const gender = faker.name.gender(true); // <-- returns a string
const firstName = faker.name.firstName(gender);
const middleName = faker.name.middleName(gender);
Unfortunately, Faker's faker.name.firstName(gender) takes a GenderType enum value, not a string, even though you can use it like faker.name.firstName('male'). That works, but using the variable gender doesn't work.
Am I missing something here?

faker.name.firstName has the type (gender?: GenderType) => string, where type GenderType = 'female' | 'male' | 0 | 1;*.
However, faker.name.gender has the type (binary?: boolean = false) => string. It can return quite a broad range of values:
> faker.name.gender()
'T* woman'
> faker.name.gender()
'Intersex'
> faker.name.gender()
'Cis'
Unhelpfully, even if you set binary to true, what it returns is "Female" or "Male", neither of which is actually a GenderType:
> faker.name.gender(true)
'Male'
> faker.name.gender(true)
'Female'
although there is some normalisation, so this works in JavaScript (but not TypeScript):
> faker.name.firstName("Male")
'Ilene'
To make this work you'd have to add some type assertions, for example:
import { faker, GenderType } from "#faker-js/faker";
const gender = faker.name.gender(true).toLowerCase() as GenderType;
// ^ we know this will be true
const name = faker.name.firstName(gender);
or, if you want to work with the capitalised version, using the intrinisic string manipulation types:
const gender = faker.name.gender(true) as "Female" | "Male";
// ^ we know this will be true
// ...
const name = faker.name.firstName(gender.toLowerCase() as Lowercase<typeof gender>);
// ^ this is obviously true
// (if ugly...)
These seem awkward enough that I've opened a bug to explore whether it can be fixed upstream.
(Also it looks like the string case typing is being explored in TypeScript, so maybe the as Lowercase won't be needed at some point.)
* The numerical values are deprecated:
> faker.name.firstName(0)
[#faker-js/faker]: name.firstName(number) is deprecated since v6.1.0 and will be removed in v7.0.0. Please use 'female' or 'male' instead.
'Forrest'

Related

Update a Map in groovy spock framework

I have the below spock specification and want to update the map from data table. Can some body help achieve this
def "groovy map update"() {
setup: "step1"
Map json = [
user :[
name : 'ABC'
]]
when: "step2"
println ('Before modification:')
println (json)
then: "step3"
json.with {
//user.name = value // this one works
(field) = value // this one does not work
}
println ('After modification:')
println (json)
where:
field | value
'user.name' | 'XYZ'
}
The then section is intended for asserts and not for updates etc. So you have to update the map in the when section and then test the result in the then section. For example like this:
def "groovy map update"() {
setup: 'create json'
Map json = [user: [name: 'ABC']]
when: 'update it'
def target = json
for (node in path - path.last()) {
target = target[node]
}
target[path.last()] = value
then: 'check the assignment'
json.user.name == value
where:
path | value
['user', 'name'] | 'XYZ'
}
One way how to update nested Map value can be by using list of path nodes instead of field notation and then iterate over them to obtain the last Map instance and set the value there:
def target = json
for (node in path - path.last()) {
target = target[node]
}
target[path.last()] = value
The accepted solution is correct, I just want to show an alternative doing the same in a slightly different way, assuming you want to stick with the dotted notation for field in your where: block. I just added two more test cases in order to make sure it works as expected.
#Unroll
def "set #field to #value"() {
setup: 'create json'
Map json = [user: [name: 'ABC', address: [street: '21 Main St', zip: '12345', city: 'Hometown']]]
when: 'update it'
def subMap = json
field.split("[.]").each {
if (subMap[it] instanceof Map)
subMap = subMap[it]
else
subMap[it] = value
}
println json
then: 'check the assignment'
json.newField == value ||
json.user.name == value ||
json.user.address.zip == value
where:
field | value
'newField' | 'dummy'
'user.name' | 'XYZ'
'user.address.zip' | '98765'
}
Update: If you want to save a few lines of code you can also use a fold (or reduce or accumulate) operation via inject(..) as described here
#Unroll
def "set #field to #value"() {
setup: 'create json'
Map json = [user: [name: 'ABC', address: [street: '21 Main St', zip: '12345', city: 'Hometown']]]
when: 'update it'
field.split("[.]").inject(json) { subMap, key ->
subMap[key] instanceof Map ? subMap[key] : subMap.put(key, value)
}
println json
then: 'check the assignment'
json.newField == value ||
json.user.name == value ||
json.user.address.zip == value
where:
field | value
'newField' | 'dummy'
'user.name' | 'XYZ'
'user.address.zip' | '98765'
}
Whether you find that readable or not may depend on your familiarity with topics like functional programming in general or map/reduce in particular. The charm here in addition to brevity is that we no longer need a local variable outside of our closure but we just inject (hence the method name) the result of iteration n to iteration n+1.
BTW, as a nice side effect inject(..) as I am using it here returns the previous value of the value you set or overwrite. Just add println in front of field.split("[.]").inject(json) ... in order to see it.
Update 2: Please note that both variants only work if there is no existing field value of type Map in the target field because of the instanceof Map check heuristics in my code. I.e. these two cases would not work:
'user.address' | [street: '23 Test Blvd', zip: '33333', city: 'Somewhere']
'user.address' | '23 Test Blvd, 33333 Somewhere'
This one would work, though, because there is no preexisting value:
'user.alternativeAddress' | [street: '23 Test Blvd', zip: '33333', city: 'Somewhere']

node uri regex not capturing capture groups

I know there are a billion regex questions on stackoverflow, but I can't understand why my uri matcher isn't working in node.
I have the following:
var uri = "file:tmp.db?mode=ro"
function parseuri2db(uri){
var regex = new RegExp("(?:file:)(.*)(?:\\?.*)");
let dbname = uri.match(regex)
return dbname
}
I'm trying to identify only the database name, which I expect to be:
After an uncaptured file: group
Before an optional ? + parameters to end of string.
While I'm using:
var regex1 = new RegExp("(?:file:)(.*)(?:\\?.*)");
I thought the answer was actually more like:
var regex2 = new RegExp("(?:file:)(.*)(?:\\??.*)");
With a 0 or 1 ? quantifier on the \\? literal. But the latter fails.
Anyway, my result is:
console.log(parseuri2db(conf.db_in.filename))
[ 'file:tmp.db?mode=ro',
'tmp.db',
index: 0,
input: 'file:tmp.db?mode=ro' ]
Which seems to be capturing the whole string in the first argument, rather than just the single capture group I asked for.
My questions are:
What am I doing wrong that I'm getting multiple captures?
How can I rephrase this to capture my capture groups with names?
I expected something like the following to work for (2):
function parseuri2db(uri){
// var regex = new RegExp("(?:file:)(.*)(?:\\?.*)");
// let dbname = uri.match(regex)
var regex = new RegExp("(?<protocol>file:)(?<fname>.*)(<params>\\?.*)");
let [, protocol, fname, params] = uri.match(regex)
return dbname
}
console.log(parseuri2db(conf.db_in.filename))
But:
SyntaxError: Invalid regular expression: /(?<protocol>file:)(?<fname>.*)(<params>\?.*)/: Invalid group
Update 1
Answer to my first question is that I needed to not capture the ? literal in the second capture group:
"(?:file:)([^?]*)(?:\\??.*)"
That particular node regex library does not support groups.

How can I search and return the values and pass it to the method from spock table

Currently implementing GEB,Spock,Groovy. I come across the scenario like
There is a set of data's in the spock table. I have to pass the modulename as a parameter, Search from the spock table then return two values user id and password. Below code is skeleton code
My question is how to search module name based on parameter?
How to return two data's ?
Class Password_Collection extends Specification {
def "Secure password for search and Data Driven"(String ModuleName) {
expect:
// Search based on modulename in where
// pick the values and return the picked data
where:
Module | User_Name | Pass_word
login_Pass | cqauthor1 | SGVsbG8gV29ybGQ =
AuthorPageTest_Pass | cqauthor2 | DOIaRTd35f3y4De =
PublisherPage_pass | cqaauthor3 | iFK95JKasdfdO5 ==
}
}
If you provide the code it would be great help to learn and imeplement.
You don't need to search the table yourself or pick that data. Spock will do that automatically for you
In the expect: block just write your unit test that uses Module, User_Name and Pass_word. Spock will automatically run the test 3 times (as many as the rows of the table) passing each row in turn to your test.
Remove the argument ModuleName from the test method. It is not needed.
I suggest you read the Spock documentation on Data Driven tests a bit more.
class YourSpec extends Specification {
def "Secure password for search and Data Driven"(Module, User_Name, Pass_Word) {
expect:
classUnderTest.getUserNameForModule(Module) == User_Name
classUnderTest.getPasswordForModule(Module) == Pass_Word
where:
Module | User_Name | Pass_word
login_Pass | cqauthor1 | SGVsbG8gV29ybGQ =
AuthorPageTest_Pass | cqauthor2 | DOIaRTd35f3y4De =
PublisherPage_pass | cqaauthor3 | iFK95JKasdfdO5 ==
}
}
What Spock will do is run your test one time for each row in the data table from the "where" block, passing Module, User_Name, Pass_Word as parameters and assert your expectations in the "expect" block.
Please refer to Spock Data Driven Testing documentation for more details.

Data driven tests in Spock

I'm rewriting some JUnit test into Spock to take advantage of the data driven test style.
I'm struggling a bit with how to provide the verification with something dynamic.
Here's what I have so far:
def "domestic rules"(from, to, oneWay, check) {
expect:
String mealResponse = getMealResponse(new BookingOptions.BookingOptionsBuilder().setFrom(from).setTo(to).setOneWay(oneWay).build());
check(mealResponse)
where:
from | to | oneWay || check
'MNL' | 'PEK' | true || assertNoMeals()
}
def assertNoMeals = {
assert JsonAssert.with(it)
.assertThat('$.links', hasSize(1))
.assertThat('$.links[0].rel', is("http://localhost:9001/api/docs/rels/ink/meal-allocations"))
.assertThat('$.links[0].uri', startsWith("http://localhost:9001/api/tenants/acme/meals/allocations/"));
}
Unfortunately, I get a NullPointerException at the line with the first row of data.
I guess thats because the closure is being run at that point, rather than just declared.
Is there a way to do this better?
Change
def "domestic rules"(from, to, oneWay, check) {
To
#Unroll
def "domestic rules from #from to #to one way #oneWay"() {
def "domestic rules"() {
when: 'get meals using certain parameters'
String mealResponse = getMealResponse(new BookingOptions.BookingOptionsBuilder().setFrom(from).setTo(to).setOneWay(oneWay).build())
then: 'the json response should contain some contents (improve the message here!)'
JsonAssert.with(mealResponse)
.assertThat('$.links', hasSize(1))
.assertThat('$.links[0].rel', is(somethingToUseInAssertions))
where:
from | to | oneWay || somethingToUseInAssertions
'MNL' | 'PEK' | true || 'just some example'
}
The above should help you get in the right track. Notice that you should have some values only in the examples. If you need some logic in the assertions, use a value which indicates what kind of assertion needs to be made... but it's a very bad idea to use a closure as an example.
If you really want to make your test hard to maintain and go ahead and use closures as "values" in your examples, then do something like this:
def "domestic rules"() {
when:
String mealResponse = getMealResponse(new BookingOptions.BookingOptionsBuilder().setFrom(from).setTo(to).setOneWay(oneWay).build())
then:
check(mealResponse)
where:
from | to | oneWay || check
'MNL' | 'PEK' | true || this.&assertNoMeals
}
boolean assertNoMeals(mealResponse) {
assert JsonAssert.with(mealResponse)
.assertThat('$.links', hasSize(1))
.assertThat('$.links[0].rel', is("http://localhost:9001/api/docs/rels/ink/meal-allocations"))
.assertThat('$.links[0].uri', startsWith("http://localhost:9001/api/tenants/acme/meals/allocations/"))
return true // pass!
}
I advise you to learn both Groovy and Spock before writing something that is more reasonable. It's not hard, but it does take at least a few hours!

Mapping list to Map not working

I have a map
["name1":["field1":value1, "field2":value2, "field3":value3],
"name2":["field1":value4, "field2":value5, "field3":value6],
"name3":["field1":value7, "field2":value8, "field3":value9]]
and a list
[name1, name3]
I wanted a result as
["name1":["field1":value1, "field2":value2, "field3":value3],
"name3":["field1":value7, "field2":value8, "field3":value9]]
The code used
result = recomendationOffers.inject( [:] ) { m, v ->
if( !m[ v ] ) {
m[ v ] = []
}
m[ v ] << tariffRecMap[ v.toString() ]
m
}
Now the datatype of the name1 changed from Varchar2(35) to number(10).
I expected the same logic to work but it is not working and I am getting values
["name1":[null], "name3":[null]]
also the value such as 1000000959 is displayed as 1.000000959E9, is this making any difference ?
posting the original values
When I was handling with string, it looked as below
["FBUN-WEB-VIRGIN-10-24-08":["FIXEDLN_ALLOWANCE":0.0,
"OFFER_VERSION_ID":1.000013082E9, "OFFER_TYPE_DESC":"Contract",
"OFFER_NAME":"PM_V 10 50+250 CA", "SMS_ALLOWANCE":250.0,
"VM_TARIFF_FLAG":"N", "IPHONE_IND":"N", "OFFER_MRC":10.5,
"ALLOWANCE08":0.0, "DATA_ALLOWANCE":524288.0, "BB_IND":"N",
"CONTRACT_TERM":24.0, "OFFER_CODE":"FBUN-WEB-VIRGIN-10-24-08",
"ONNET_TEXT_ALLOWANCE":0.0, "VOICE_ALLOWANCE":50.0,
"MMS_ALLOWANCE":0.0, "ONNET_ALLOWANCE":0.0],
Now after the database datatype changed to number from varchar it looks as below where the value in DB is 1000010315
[1.000010315E9:["FIXEDLN_ALLOWANCE":0.0,
"OFFER_VERSION_ID":1.000010315E9, "OFFER_TYPE_DESC":"Sup Voice",
"OFFER_NAME":"VIP - 35 c", "SMS_ALLOWANCE":60000.0,
"VM_TARIFF_FLAG":"N", "IPHONE_IND":"N", "OFFER_MRC":35.0,
"ALLOWANCE08":45000.0, "DATA_ALLOWANCE":2.147483648E9, "BB_IND":"N",
"CONTRACT_TERM":24.0, "OFFER_CODE":"FBUN-MVP-WEB-VIRGIN-35-24-20",
"ONNET_TEXT_ALLOWANCE":0.0, "VOICE_ALLOWANCE":45000.0,
"MMS_ALLOWANCE":0.0, "ONNET_ALLOWANCE":0.0]
Now the datatype of the name1 changed from Varchar2(35) to number(10) ... also the value such as 1000000959 is displayed as 1.000000959E9, is this making any difference ?
Yes, all the difference in the world. That means you're converting a Double (most likely) to a String, and as the String "1000000959" is not equal to "1.000000959E9", you don't get a match.
Not sure from the question which bits are doubles and which bits are Strings... Maybe you could expand with an actual example?
Also, your inject method can be replaced with:
def result = tariffRecMap.subMap( recomendationOffers )

Resources