2023-07-07 14:06:01 +02:00
/* eslint-disable no-useless-escape */
const { strict : assert } = require ( 'assert' ) ;
const {
defaultGanacheOptions ,
withFixtures ,
unlockWallet ,
sendTransaction ,
getEventPayloads ,
} = require ( '../helpers' ) ;
const FixtureBuilder = require ( '../fixture-builder' ) ;
/ * *
* mocks the segment api multiple times for specific payloads that we expect to
* see when these tests are run . In this case we are looking for
* 'Transaction Submitted' and 'Transaction Finalized' . In addition on the
* first event of each series we require a field that should only appear in the
* anonymized events so that we can guarantee order of seenRequests and can
* properly make assertions . Do not use the constants from the metrics
* constants files , because if these change we want a strong indicator to our
* data team that the shape of data will change .
*
* @ param { import ( 'mockttp' ) . Mockttp } mockServer
* @ returns { Promise < import ( 'mockttp/dist/pluggable-admin' ) . MockttpClientResponse > [ ] }
* /
async function mockSegment ( mockServer ) {
return [
await mockServer
. forPost ( 'https://api.segment.io/v1/batch' )
. withJsonBodyIncluding ( {
batch : [
{
type : 'track' ,
event : 'Transaction Submitted' ,
properties : { status : 'submitted' } ,
} ,
] ,
} )
. thenCallback ( ( ) => {
return {
statusCode : 200 ,
} ;
} ) ,
await mockServer
. forPost ( 'https://api.segment.io/v1/batch' )
. withJsonBodyIncluding ( {
batch : [
{
type : 'track' ,
event : 'Transaction Submitted' ,
} ,
] ,
} )
. thenCallback ( ( ) => {
return {
statusCode : 200 ,
} ;
} ) ,
await mockServer
. forPost ( 'https://api.segment.io/v1/batch' )
. withJsonBodyIncluding ( {
batch : [
{
type : 'track' ,
event : 'Transaction Finalized' ,
properties : { status : 'confirmed' } ,
} ,
] ,
} )
. thenCallback ( ( ) => {
return {
statusCode : 200 ,
} ;
} ) ,
await mockServer
. forPost ( 'https://api.segment.io/v1/batch' )
. withJsonBodyIncluding ( {
batch : [
{
type : 'track' ,
event : 'Transaction Finalized' ,
} ,
] ,
} )
. thenCallback ( ( ) => {
return {
statusCode : 200 ,
} ;
} ) ,
] ;
}
const RECIPIENT = '0x0Cc5261AB8cE458dc977078A3623E2BaDD27afD3' ;
describe ( 'Transaction Finalized Event' , function ( ) {
it ( 'Successfully tracked when sending a transaction' , async function ( ) {
await withFixtures (
{
fixtures : new FixtureBuilder ( )
. withMetaMetricsController ( {
metaMetricsId : 'fake-metrics-id' ,
participateInMetaMetrics : true ,
} )
. build ( ) ,
ganacheOptions : defaultGanacheOptions ,
title : this . test . title ,
testSpecificMock : mockSegment ,
} ,
async ( { driver , mockedEndpoint : mockedEndpoints } ) => {
await driver . navigate ( ) ;
await unlockWallet ( driver ) ;
await sendTransaction ( driver , RECIPIENT , '2.0' ) ;
const events = await getEventPayloads ( driver , mockedEndpoints ) ;
// The order of these events is ensured by the mockSegment function
// which requires that the first, and third (0, 2 indexes) have the
// status property, which will only appear on the anonymous events.
const transactionSubmittedNoMMId = events [ 0 ] ;
const transactionSubmittedWithMMId = events [ 1 ] ;
const transactionFinalizedNoMMId = events [ 2 ] ;
const transactionFinalizedWithMMId = events [ 3 ] ;
// Assert doesn't have generic matchers so we delete these timestamp related properties.
// If we switch to a different assertion library we can use generic matchers in the future.
delete transactionSubmittedNoMMId . properties . first _seen ;
delete transactionFinalizedNoMMId . properties . first _seen ;
delete transactionFinalizedNoMMId . properties . completion _time ;
// Assert that the event names begin with the appropriate prefixes. Even finalized events begin with transaction-submitted
// because they start as event fragments created when the transaction is submitted.
assert . ok (
transactionSubmittedNoMMId . messageId . startsWith (
'transaction-submitted' ,
) ,
` Transaction Submitted event with sensitive properties has messageId \" ${ transactionSubmittedNoMMId . messageId } \" does not have a messageId beginning with \" transaction-submitted \" ` ,
) ;
assert . ok (
transactionFinalizedNoMMId . messageId . startsWith (
'transaction-submitted' ,
) ,
` Transaction Finalized event with sensitive properties has messageId \" ${ transactionFinalizedNoMMId . messageId } \" that does not begin with \" transaction-submitted \" ` ,
) ;
assert . ok (
transactionSubmittedWithMMId . messageId . startsWith (
'transaction-submitted' ,
) ,
` Transaction Submitted event has messageId \" ${ transactionSubmittedWithMMId . messageId } \" that does not begin with \" transaction-submitted \" ` ,
) ;
assert . ok (
transactionFinalizedWithMMId . messageId . startsWith (
'transaction-submitted' ,
) ,
` Transaction Finalized event has messageID \" ${ transactionFinalizedWithMMId . messageId } \" that does not begin with \" transaction-submitted \" ` ,
) ;
// Assert that the events with sensitive properties should have messageIds ending in 0x000
// This is important because otherwise the events are seen as duplicates in segment
assert . ok (
transactionSubmittedNoMMId . messageId . endsWith ( '0x000' ) ,
` Transaction Submitted event with sensitive properties has messageId \" ${ transactionSubmittedNoMMId . messageId } \" that does not end in \" 0x000 \" to differentiate it from the event that does not include sensitive data. ` ,
) ;
assert . ok (
transactionFinalizedNoMMId . messageId . endsWith ( '0x000' ) ,
` Transaction Finalized event with sensitive properties has messageID \" ${ transactionFinalizedNoMMId . messageId } \" that does not end in \" 0x000 \" to differentiate it from the event that does not include sensitive data. ` ,
) ;
// Assert that transaction finalized events contain '-success-' in their messageId
assert . ok (
transactionFinalizedWithMMId . messageId . includes ( '-success-' ) ,
` Transaction Finalized event has messageId \" ${ transactionFinalizedWithMMId . messageId } \" that does not contain "-success-" ` ,
) ;
assert . ok (
transactionFinalizedNoMMId . messageId . includes ( '-success-' ) ,
` Transaction Finalized event with sensitive properties has messageID \" ${ transactionFinalizedNoMMId . messageId } \" that does not contain "-success-" ` ,
) ;
// Assert that the events with sensitive data do not contain a userId (the random anonymous id generated when a user opts into metametrics)
assert . ok (
typeof transactionSubmittedNoMMId . userId === 'undefined' ,
'Transaction Submitted event with sensitive properties has a userId supplied when it should only have the anonymousId' ,
) ;
assert . ok (
typeof transactionFinalizedNoMMId . userId === 'undefined' ,
'Transaction Finalized event with sensitive properties has a userId supplied when it should only have the anonymousId' ,
) ;
// Assert that the events with sensitive data have anonymousId set to 0x0000000000000000 which is our universal anonymous record
assert . ok (
transactionSubmittedNoMMId . anonymousId === '0x0000000000000000' ,
'Transaction Submitted event with sensitive properties has an anonymousId that does not match our universal anonymous id of 0x0000000000000000' ,
) ;
assert . ok (
transactionFinalizedNoMMId . anonymousId === '0x0000000000000000' ,
'Transaction Finalized event with sensitive properties has an anonymousId that does not match our universal anonymous id of 0x0000000000000000' ,
) ;
// Assert that our events without sensitive data have a userId but no anonymousId
assert . ok (
typeof transactionSubmittedWithMMId . userId === 'string' &&
typeof transactionSubmittedWithMMId . anonymousId === 'undefined' ,
'Transaction Submitted event without sensitive properties should only have a userId specified, and no anonymousId' ,
) ;
assert . ok (
typeof transactionFinalizedWithMMId . userId === 'string' &&
typeof transactionFinalizedWithMMId . anonymousId === 'undefined' ,
'Transaction Finalized event without sensitive properties should only have a userId specified, and no anonymousId' ,
) ;
// Assert on the properties
assert . deepStrictEqual (
transactionSubmittedNoMMId . properties ,
{
status : 'submitted' ,
transaction _envelope _type : 'legacy' ,
gas _limit : '0x5208' ,
gas _price : '2' ,
default _gas : '0.000021' ,
default _gas _price : '2' ,
chain _id : '0x539' ,
referrer : 'metamask' ,
source : 'user' ,
network : '1337' ,
eip _1559 _version : '0' ,
gas _edit _type : 'none' ,
gas _edit _attempted : 'none' ,
account _type : 'MetaMask' ,
device _model : 'N/A' ,
asset _type : 'NATIVE' ,
token _standard : 'NONE' ,
transaction _type : 'simpleSend' ,
transaction _speed _up : false ,
ui _customizations : null ,
category : 'Transactions' ,
locale : 'en' ,
environment _type : 'background' ,
} ,
'Transaction Submitted event with sensitive properties does not match the expected payload' ,
) ;
assert . deepStrictEqual (
transactionSubmittedWithMMId . properties ,
{
chain _id : '0x539' ,
referrer : 'metamask' ,
source : 'user' ,
network : '1337' ,
eip _1559 _version : '0' ,
gas _edit _type : 'none' ,
gas _edit _attempted : 'none' ,
account _type : 'MetaMask' ,
device _model : 'N/A' ,
asset _type : 'NATIVE' ,
token _standard : 'NONE' ,
transaction _type : 'simpleSend' ,
transaction _speed _up : false ,
ui _customizations : null ,
category : 'Transactions' ,
locale : 'en' ,
environment _type : 'background' ,
2023-07-28 20:08:59 +02:00
status : 'submitted' ,
2023-07-07 14:06:01 +02:00
} ,
'Transaction Submitted event without sensitive properties does not match the expected payload' ,
) ;
assert . deepStrictEqual (
transactionFinalizedNoMMId . properties ,
{
status : 'confirmed' ,
transaction _envelope _type : 'legacy' ,
gas _limit : '0x5208' ,
gas _price : '2' ,
default _gas : '0.000021' ,
default _gas _price : '2' ,
chain _id : '0x539' ,
referrer : 'metamask' ,
source : 'user' ,
network : '1337' ,
eip _1559 _version : '0' ,
gas _edit _type : 'none' ,
gas _edit _attempted : 'none' ,
account _type : 'MetaMask' ,
device _model : 'N/A' ,
asset _type : 'NATIVE' ,
token _standard : 'NONE' ,
transaction _type : 'simpleSend' ,
transaction _speed _up : false ,
ui _customizations : null ,
gas _used : '5208' ,
category : 'Transactions' ,
locale : 'en' ,
environment _type : 'background' ,
} ,
'Transaction Finalized event with sensitive properties does not match the expected payload' ,
) ;
assert . deepStrictEqual (
transactionFinalizedWithMMId . properties ,
{
chain _id : '0x539' ,
referrer : 'metamask' ,
source : 'user' ,
network : '1337' ,
eip _1559 _version : '0' ,
gas _edit _type : 'none' ,
gas _edit _attempted : 'none' ,
account _type : 'MetaMask' ,
device _model : 'N/A' ,
asset _type : 'NATIVE' ,
token _standard : 'NONE' ,
transaction _type : 'simpleSend' ,
transaction _speed _up : false ,
ui _customizations : null ,
category : 'Transactions' ,
locale : 'en' ,
environment _type : 'background' ,
2023-07-28 20:08:59 +02:00
status : 'confirmed' ,
2023-07-07 14:06:01 +02:00
} ,
'Transaction Finalized event without sensitive properties does not match the expected payload' ,
) ;
} ,
) ;
} ) ;
} ) ;