@@ -58,7 +58,6 @@ import setCookieParser from 'set-cookie-parser';
58
58
import { postsFixture } from './fixture/post' ;
59
59
import { sourcesFixture } from './fixture/source' ;
60
60
import { SourcePermissions } from '../src/schema/sources' ;
61
- import { getEncryptedFeatures } from '../src/growthbook' ;
62
61
import { base64 } from 'graphql-relay/utils/base64' ;
63
62
import { cookies } from '../src/cookies' ;
64
63
import { signJwt } from '../src/auth' ;
@@ -69,11 +68,12 @@ import {
69
68
} from '../src/common' ;
70
69
import { saveReturnAlerts } from '../src/schema/alerts' ;
71
70
import { CoresRole , UserVote } from '../src/types' ;
72
- import { BootAlerts , excludeProperties } from '../src/routes/boot' ;
71
+ import { BootAlerts , excludeProperties , FunnelBoot } from '../src/routes/boot' ;
73
72
import { SubscriptionCycles } from '../src/paddle' ;
74
73
import * as njordCommon from '../src/common/njord' ;
75
74
import { Credits , EntityType } from '@dailydotdev/schema' ;
76
75
import { createClient } from '@connectrpc/connect' ;
76
+ import { FunnelState } from '../src/integrations/freyja' ;
77
77
78
78
let app : FastifyInstance ;
79
79
let con : DataSource ;
@@ -169,6 +169,18 @@ const getBootAlert = (data: Alerts): BootAlerts =>
169
169
subDays ( new Date ( ) , FEED_SURVEY_INTERVAL ) > data . lastFeedSettingsFeedback ,
170
170
} ) as BootAlerts ;
171
171
172
+ jest . mock ( '../src/growthbook' , ( ) => ( {
173
+ ...( jest . requireActual ( '../src/growthbook' ) as Record < string , unknown > ) ,
174
+ getEncryptedFeatures : ( ) => 'enc' ,
175
+ getUserGrowthBookInstace : ( ) => {
176
+ return {
177
+ loadFeatures : jest . fn ( ) ,
178
+ getFeatures : jest . fn ( ) ,
179
+ getFeatureValue : ( ) => 'gbId' ,
180
+ } ;
181
+ } ,
182
+ } ) ) ;
183
+
172
184
beforeAll ( async ( ) => {
173
185
con = await createOrGetConnection ( ) ;
174
186
state = await initializeGraphQLTesting ( ( ) => new MockContext ( con ) ) ;
@@ -177,7 +189,6 @@ beforeAll(async () => {
177
189
178
190
beforeEach ( async ( ) => {
179
191
jest . clearAllMocks ( ) ;
180
- jest . mocked ( getEncryptedFeatures ) . mockReturnValue ( 'enc' ) ;
181
192
await con . getRepository ( User ) . save ( usersFixture [ 0 ] ) ;
182
193
await con . getRepository ( Source ) . save ( sourcesFixture ) ;
183
194
await con . getRepository ( Post ) . save ( postsFixture ) ;
@@ -1486,3 +1497,170 @@ describe('boot alerts shouldShowFeedFeedback property', () => {
1486
1497
expect ( res . body . alerts . shouldShowFeedFeedback ) . toBeTruthy ( ) ;
1487
1498
} ) ;
1488
1499
} ) ;
1500
+
1501
+ describe ( 'funnel boot' , ( ) => {
1502
+ const FUNNEL_DATA : FunnelState = {
1503
+ session : {
1504
+ userId : '1' ,
1505
+ id : 'sessionId' ,
1506
+ currentStep : '5' ,
1507
+ } ,
1508
+ funnel : {
1509
+ id : 'funnelId' ,
1510
+ version : 2 ,
1511
+ } ,
1512
+ } ;
1513
+
1514
+ const FUNNEL_BOOT_BODY : FunnelBoot = {
1515
+ ...ANONYMOUS_BODY ,
1516
+ funnelState : FUNNEL_DATA ,
1517
+ } ;
1518
+
1519
+ it ( 'should return the funnel data for an anonymous user' , async ( ) => {
1520
+ nock ( process . env . FREYJA_ORIGIN )
1521
+ . post ( '/api/sessions' , {
1522
+ userId : '1' ,
1523
+ funnelId : 'funnelId' ,
1524
+ version : 2 ,
1525
+ } )
1526
+ . reply ( 200 , JSON . stringify ( FUNNEL_DATA ) ) ;
1527
+
1528
+ const res = await request ( app . server )
1529
+ . get ( `${ BASE_PATH } /funnel?id=funnelId&v=2` )
1530
+ . set ( 'User-Agent' , TEST_UA )
1531
+ . set ( 'Cookie' , `${ cookies . tracking . key } =1;` )
1532
+ . expect ( 200 ) ;
1533
+ expect ( res . body ) . toEqual ( FUNNEL_BOOT_BODY ) ;
1534
+ } ) ;
1535
+
1536
+ it ( 'should return the logged in user' , async ( ) => {
1537
+ nock ( process . env . FREYJA_ORIGIN )
1538
+ . post ( '/api/sessions' )
1539
+ . reply ( 200 , JSON . stringify ( FUNNEL_DATA ) ) ;
1540
+
1541
+ const accessToken = await signJwt (
1542
+ {
1543
+ userId : '1' ,
1544
+ roles : [ ] ,
1545
+ } ,
1546
+ 15 * 60 * 1000 ,
1547
+ ) ;
1548
+
1549
+ const res = await request ( app . server )
1550
+ . get ( `${ BASE_PATH } /funnel?id=funnelId` )
1551
+ . set ( 'User-Agent' , TEST_UA )
1552
+ . set (
1553
+ 'Cookie' ,
1554
+ `${ cookies . auth . key } =${ app . signCookie ( accessToken . token ) } ;` ,
1555
+ )
1556
+ . expect ( 200 ) ;
1557
+ expect ( res . body ) . toEqual ( {
1558
+ ...FUNNEL_BOOT_BODY ,
1559
+ user : excludeProperties ( LOGGED_IN_BODY . user , [
1560
+ 'balance' ,
1561
+ 'flags' ,
1562
+ 'isPlus' ,
1563
+ 'isTeamMember' ,
1564
+ 'language' ,
1565
+ 'roles' ,
1566
+ 'subscriptionFlags' ,
1567
+ ] ) ,
1568
+ } ) ;
1569
+ } ) ;
1570
+
1571
+ it ( 'should return anonymous user if jwt is expired' , async ( ) => {
1572
+ nock ( process . env . FREYJA_ORIGIN )
1573
+ . post ( '/api/sessions' )
1574
+ . reply ( 200 , JSON . stringify ( FUNNEL_DATA ) ) ;
1575
+
1576
+ const accessToken = await signJwt (
1577
+ {
1578
+ userId : '1' ,
1579
+ roles : [ ] ,
1580
+ } ,
1581
+ - 15 * 60 * 1000 ,
1582
+ ) ;
1583
+
1584
+ const res = await request ( app . server )
1585
+ . get ( `${ BASE_PATH } /funnel?id=funnelId` )
1586
+ . set ( 'User-Agent' , TEST_UA )
1587
+ . set (
1588
+ 'Cookie' ,
1589
+ `${ cookies . auth . key } =${ app . signCookie ( accessToken . token ) } ;` ,
1590
+ )
1591
+ . expect ( 200 ) ;
1592
+ expect ( res . body ) . toEqual ( FUNNEL_BOOT_BODY ) ;
1593
+ } ) ;
1594
+
1595
+ it ( 'should set cookie for the new funnel' , async ( ) => {
1596
+ nock ( process . env . FREYJA_ORIGIN )
1597
+ . post ( '/api/sessions' )
1598
+ . reply ( 200 , JSON . stringify ( FUNNEL_DATA ) ) ;
1599
+
1600
+ const res = await request ( app . server )
1601
+ . get ( `${ BASE_PATH } /funnel?id=funnelId` )
1602
+ . set ( 'User-Agent' , TEST_UA )
1603
+ . set ( 'Cookie' , `${ cookies . tracking . key } =1;` )
1604
+ . expect ( 200 ) ;
1605
+
1606
+ const cookie = ( res . get ( 'set-cookie' ) as unknown as string [ ] ) . find ( ( c ) =>
1607
+ c . startsWith ( cookies . funnel . key ) ,
1608
+ ) ;
1609
+ expect ( cookie ?. split ( ';' ) [ 0 ] ) . toEqual (
1610
+ `${ cookies . funnel . key } =${ FUNNEL_DATA . session . id } ` ,
1611
+ ) ;
1612
+ } ) ;
1613
+
1614
+ it ( 'should load funnel when cookie is present' , async ( ) => {
1615
+ nock ( process . env . FREYJA_ORIGIN )
1616
+ . get ( `/api/sessions/${ FUNNEL_DATA . session . id } ` )
1617
+ . reply ( 200 , JSON . stringify ( FUNNEL_DATA ) ) ;
1618
+
1619
+ const res = await request ( app . server )
1620
+ . get ( `${ BASE_PATH } /funnel?id=funnelId2` )
1621
+ . set ( 'User-Agent' , TEST_UA )
1622
+ . set (
1623
+ 'Cookie' ,
1624
+ `${ cookies . tracking . key } =1;${ cookies . funnel . key } =${ FUNNEL_DATA . session . id } ;` ,
1625
+ )
1626
+ . expect ( 200 ) ;
1627
+ expect ( res . body ) . toEqual ( FUNNEL_BOOT_BODY ) ;
1628
+ } ) ;
1629
+
1630
+ it ( 'should ignore cookie when the user does not match' , async ( ) => {
1631
+ nock ( process . env . FREYJA_ORIGIN )
1632
+ . get ( `/api/sessions/${ FUNNEL_DATA . session . id } ` )
1633
+ . reply ( 200 , JSON . stringify ( FUNNEL_DATA ) ) ;
1634
+
1635
+ const clone = structuredClone ( FUNNEL_DATA ) ;
1636
+ clone . session . userId = '2' ;
1637
+ nock ( process . env . FREYJA_ORIGIN )
1638
+ . post ( '/api/sessions' )
1639
+ . reply ( 200 , JSON . stringify ( clone ) ) ;
1640
+
1641
+ const res = await request ( app . server )
1642
+ . get ( `${ BASE_PATH } /funnel?id=funnelId` )
1643
+ . set ( 'User-Agent' , TEST_UA )
1644
+ . set (
1645
+ 'Cookie' ,
1646
+ `${ cookies . tracking . key } =2;${ cookies . funnel . key } =${ FUNNEL_DATA . session . id } ;` ,
1647
+ )
1648
+ . expect ( 200 ) ;
1649
+ expect ( res . body . funnelState . session . userId ) . toEqual ( '2' ) ;
1650
+ } ) ;
1651
+
1652
+ it ( 'should load funnel id from growthbook' , async ( ) => {
1653
+ nock ( process . env . FREYJA_ORIGIN )
1654
+ . post ( '/api/sessions' , {
1655
+ userId : '1' ,
1656
+ funnelId : 'gbId' ,
1657
+ } )
1658
+ . reply ( 200 , JSON . stringify ( FUNNEL_DATA ) ) ;
1659
+
1660
+ await request ( app . server )
1661
+ . get ( `${ BASE_PATH } /funnel` )
1662
+ . set ( 'User-Agent' , TEST_UA )
1663
+ . set ( 'Cookie' , `${ cookies . tracking . key } =1;` )
1664
+ . expect ( 200 ) ;
1665
+ } ) ;
1666
+ } ) ;
0 commit comments