import { pick } from "lodash/fp" ; import { format as formatDate } from "date-fns" ; import { isMobile } from "./utils" ; Cypress . Commands . add ( "getBySel" , ( selector , ... args ) => { return cy . get ( `[data-test=${ selector }]` , ... args ) ; } ) ; Cypress . Commands . add ( "getBySelLike" , ( selector , ... args ) => { return cy . get ( `[data-test*=${ selector }]` , ... args ) ; } ) ; Cypress . Commands . add ( "login" , ( username , password , rememberUser = false ) => { const signinPath = "/signin" ; const log = Cypress . log ( { name : "login" , displayName : "LOGIN" , message : [ `🔐 Authenticating | ${ username }` ] , autoEnd : false , } ) ; cy . server ( ) ; cy . route ( "POST" , "/login" ) . as ( "loginUser" ) ; cy . route ( "GET" , "checkAuth" ) . as ( "getUserProfile" ) ; cy . location ( "pathname" , { log : false } ) . then ( ( currentPath ) => { if ( currentPath !== signinPath ) { cy . visit ( signinPath ) ; } } ) ; log . snapshot ( "before" ) ; cy . getBySel ( "signin-username" ) . type ( username ) ; cy . getBySel ( "signin-password" ) . type ( password ) ; if ( rememberUser ) { cy . getBySel ( "signin-remember-me" ) . find ( "input" ) . check ( ) ; } cy . getBySel ( "signin-submit" ) . click ( ) ; cy . wait ( "@loginUser" ) . then ( ( loginUser ) => { log . set ( { consoleProps ( ) { return { username , password , rememberUser , userId : loginUser . response . body . user ?. id , } ; } , } ) ; log . snapshot ( "after" ) ; log . end ( ) ; } ) ; } ) ; Cypress . Commands . add ( "loginByApi" , ( username , password = Cypress . env ( "defaultPassword" ) ) => { return cy . request ( "POST" , `${ Cypress . env ( "apiUrl" ) }/login` , { username , password , } ) ; } ) ; Cypress . Commands . add ( "reactComponent" , { prevSubject : "element" } , ( $el ) => { if ( $el . length !== 1 ) { throw new Error ( `cy.component() requires element of length 1 but got ${ $el . length }` ) ; } const key = Object . keys ( $el . get ( 0 ) ) . find ( ( key ) => key . startsWith ( "__reactInternalInstance$" ) ) ; const domFiber = $el . prop ( key ) ; Cypress . log ( { name : "component" , consoleProps ( ) { return { component : domFiber , } ; } , } ) ; return domFiber . return ; } ) ; Cypress . Commands . add ( "setTransactionAmountRange" , ( min , max ) => { cy . getBySel ( "transaction-list-filter-amount-range-button" ) . scrollIntoView ( ) . click ( { force : true } ) ; return cy . getBySelLike ( "filter-amount-range-slider" ) . reactComponent ( ) . its ( "memoizedProps" ) . invoke ( "onChange" , null , [ min / 10 , max / 10 ] ) ; } ) ; Cypress . Commands . add ( "loginByXstate" , ( username , password = Cypress . env ( "defaultPassword" ) ) => { const log = Cypress . log ( { name : "loginbyxstate" , displayName : "LOGIN BY XSTATE" , message : [ `🔐 Authenticating | ${ username }` ] , autoEnd : false , } ) ; cy . server ( ) ; cy . route ( "POST" , "/login" ) . as ( "loginUser" ) ; cy . route ( "GET" , "/checkAuth" ) . as ( "getUserProfile" ) ; cy . visit ( "/signin" , { log : false } ) . then ( ( ) => { log . snapshot ( "before" ) ; } ) ; cy . window ( { log : false } ) . then ( ( win ) => win . authService . send ( "LOGIN" , { username , password } ) ) ; return cy . wait ( "@loginUser" ) . then ( ( loginUser ) => { log . set ( { consoleProps ( ) { return { username , password , userId : loginUser . response . body . user . id , } ; } , } ) ; log . snapshot ( "after" ) ; log . end ( ) ; } ) ; } ) ; Cypress . Commands . add ( "logoutByXstate" , ( ) => { cy . server ( ) ; cy . route ( "POST" , "/logout" ) . as ( "logoutUser" ) ; const log = Cypress . log ( { name : "logoutByXstate" , displayName : "LOGOUT BY XSTATE" , message : [ `🔒 Logging out current user` ] , autoEnd : false , } ) ; cy . window ( { log : false } ) . then ( ( win ) => { log . snapshot ( "before" ) ; win . authService . send ( "LOGOUT" ) ; } ) ; return cy . wait ( "@logoutUser" ) . then ( ( ) => { log . snapshot ( "after" ) ; log . end ( ) ; } ) ; } ) ; Cypress . Commands . add ( "switchUser" , ( username ) => { cy . logoutByXstate ( ) ; return cy . loginByXstate ( username ) . then ( ( ) => { if ( isMobile ( ) ) { cy . getBySel ( "sidenav-toggle" ) . click ( ) ; cy . getBySel ( "sidenav-username" ) . contains ( username ) ; cy . getBySel ( "sidenav-toggle" ) . click ( { force : true } ) ; } else { cy . getBySel ( "sidenav-username" ) . contains ( username ) ; } cy . getBySel ( "list-skeleton" ) . should ( "not.be.visible" ) ; cy . getBySelLike ( "transaction-item" ) . should ( "have.length.greaterThan" , 1 ) ; cy . percySnapshot ( `Switch to User ${ username }` ) ; } ) ; } ) ; Cypress . Commands . add ( "createTransaction" , ( payload ) => { const log = Cypress . log ( { name : "createTransaction" , displayName : "CREATE TRANSACTION" , message : [ `💸 (${ payload . transactionType }): ${ payload . sender . id } <> ${ payload . receiver . id }` ] , autoEnd : false , consoleProps ( ) { return payload ; } , } ) ; return cy . window ( { log : false } ) . then ( ( win ) => { log . snapshot ( "before" ) ; win . createTransactionService . send ( "SET_USERS" , payload ) ; const createPayload = pick ( [ "amount" , "description" , "transactionType" ] , payload ) ; return win . createTransactionService . send ( "CREATE" , { ... createPayload , senderId : payload . sender . id , receiverId : payload . receiver . id , } ) ; } ) . then ( ( ) => { log . snapshot ( "after" ) ; log . end ( ) ; } ) ; } ) ; Cypress . Commands . add ( "nextTransactionFeedPage" , ( service , page ) => { const log = Cypress . log ( { name : "nextTransactionFeedPage" , displayName : "NEXT TRANSACTION FEED PAGE" , message : [ `📃 Fetching page ${ page } with ${ service }` ] , autoEnd : false , consoleProps ( ) { return { service , page , } ; } , } ) ; return cy . window ( { log : false } ) . then ( ( win ) => { log . snapshot ( "before" ) ; return win [ service ] . send ( "FETCH" , { page } ) ; } ) . then ( ( ) => { log . snapshot ( "after" ) ; log . end ( ) ; } ) ; } ) ; Cypress . Commands . add ( "pickDateRange" , ( startDate , endDate ) => { const log = Cypress . log ( { name : "pickDateRange" , displayName : "PICK DATE RANGE" , message : [ `🗓 ${ startDate . toDateString ( ) } to ${ endDate . toDateString ( ) }` ] , autoEnd : false , consoleProps ( ) { return { startDate , endDate , } ; } , } ) ; const selectDate = ( date ) => { return cy . get ( `[data-date='${ formatDate ( date , "yyyy-MM-dd" ) }']` ) . click ( { force : true } ) ; } ; cy . wrap ( startDate . getTime ( ) ) . then ( ( now ) => { log . snapshot ( "before" ) ; cy . clock ( now , [ "Date" ] ) ; } ) ; cy . getBySelLike ( "filter-date-range-button" ) . click ( { force : true } ) ; cy . get ( ".Cal__Header__root" ) . should ( "be.visible" ) ; selectDate ( startDate ) ; selectDate ( endDate ) . then ( ( ) => { log . snapshot ( "after" ) ; log . end ( ) ; } ) ; cy . get ( ".Cal__Header__root" ) . should ( "not.be.visible" ) ; } ) ; Cypress . Commands . add ( "database" , ( operation , entity , query , logTask = false ) => { const params = { entity , query , } ; const log = Cypress . log ( { name : "database" , displayName : "DATABASE" , message : [ `🔎 ${ operation }ing within ${ entity } data` ] , autoEnd : false , consoleProps ( ) { return params ; } , } ) ; return cy . task ( `${ operation }:database` , params , { log : logTask } ) . then ( ( data ) => { log . snapshot ( ) ; log . end ( ) ; return data ; } ) ; } ) ;