|
| 1 | +import { PostgresQuery } from '../../../src/adapter/PostgresQuery'; |
| 2 | +import { prepareJsCompiler } from '../../unit/PrepareCompiler'; |
| 3 | +import { dbRunner } from './PostgresDBRunner'; |
| 4 | + |
| 5 | +describe('Extensions', () => { |
| 6 | + jest.setTimeout(200 * 1000); |
| 7 | + |
| 8 | + // A three-step funnel (View -> Cart -> Purchase). Event sources are inline |
| 9 | + // `VALUES` selects so the test is fully self-contained and needs no fixture. |
| 10 | + // |
| 11 | + // Raw events (user_id, ts): |
| 12 | + // View: 1@01-01, 2@01-02, 3@01-03, 4@01-04 |
| 13 | + // Cart: 1@01-03, 2@01-20, 3@2016-12-31, 4@01-06 (timeToConvert: 5 day) |
| 14 | + // Purchase: 1@01-10 |
| 15 | + // |
| 16 | + // Cart has `timeToConvert: '5 day'`, so a Cart event only counts when it |
| 17 | + // happens after the View event and within 5 days of it: |
| 18 | + // user 1: cart 01-03 is 2 days after view 01-01 -> converts |
| 19 | + // user 2: cart 01-20 is 18 days after view 01-02 -> dropped (too late) |
| 20 | + // user 3: cart 2016-12-31 is before view 01-03 -> dropped (before) |
| 21 | + // user 4: cart 01-06 is 2 days after view 01-04 -> converts |
| 22 | + // Purchase joins off Cart, so only users who reached Cart can reach it: |
| 23 | + // user 1 purchases, user 4 does not. |
| 24 | + // |
| 25 | + // Expected conversions per step: View=4, Cart=2, Purchase=1. |
| 26 | + const { compiler, joinGraph, cubeEvaluator } = prepareJsCompiler(` |
| 27 | + const Funnels = require('Funnels'); |
| 28 | +
|
| 29 | + cube('Funnel', { |
| 30 | + extends: Funnels.eventFunnel({ |
| 31 | + userId: { sql: 'user_id' }, |
| 32 | + time: { sql: 'ts' }, |
| 33 | + steps: [ |
| 34 | + { |
| 35 | + name: 'View', |
| 36 | + eventsTable: { |
| 37 | + sql: "select user_id, ts from (values (1, timestamp '2017-01-01'), (2, timestamp '2017-01-02'), (3, timestamp '2017-01-03'), (4, timestamp '2017-01-04')) as t(user_id, ts)" |
| 38 | + } |
| 39 | + }, |
| 40 | + { |
| 41 | + name: 'Cart', |
| 42 | + timeToConvert: '5 day', |
| 43 | + eventsTable: { |
| 44 | + sql: "select user_id, ts from (values (1, timestamp '2017-01-03'), (2, timestamp '2017-01-20'), (3, timestamp '2016-12-31'), (4, timestamp '2017-01-06')) as t(user_id, ts)" |
| 45 | + } |
| 46 | + }, |
| 47 | + { |
| 48 | + name: 'Purchase', |
| 49 | + eventsTable: { |
| 50 | + sql: "select user_id, ts from (values (1, timestamp '2017-01-10')) as t(user_id, ts)" |
| 51 | + } |
| 52 | + } |
| 53 | + ] |
| 54 | + }) |
| 55 | + }) |
| 56 | + `, { allowNodeRequire: true }); |
| 57 | + |
| 58 | + async function runQueryTest(q: any, expectedResult: any) { |
| 59 | + await compiler.compile(); |
| 60 | + const query = new PostgresQuery( |
| 61 | + { joinGraph, cubeEvaluator, compiler }, |
| 62 | + { ...q, timezone: 'UTC', preAggregationsSchema: '' } |
| 63 | + ); |
| 64 | + |
| 65 | + const qp = query.buildSqlAndParams(); |
| 66 | + console.log(qp); |
| 67 | + |
| 68 | + const res = await dbRunner.testQuery(qp); |
| 69 | + console.log(JSON.stringify(res)); |
| 70 | + |
| 71 | + expect(res).toEqual(expectedResult); |
| 72 | + } |
| 73 | + |
| 74 | + describe('Funnels', () => { |
| 75 | + it('conversions per step', async () => runQueryTest({ |
| 76 | + measures: ['Funnel.conversions'], |
| 77 | + dimensions: ['Funnel.step'], |
| 78 | + order: [{ id: 'Funnel.conversions', desc: true }], |
| 79 | + }, [ |
| 80 | + { funnel__step: 'View', funnel__conversions: '4' }, |
| 81 | + { funnel__step: 'Cart', funnel__conversions: '2' }, |
| 82 | + { funnel__step: 'Purchase', funnel__conversions: '1' }, |
| 83 | + ])); |
| 84 | + |
| 85 | + it('total conversions across all steps', async () => runQueryTest({ |
| 86 | + measures: ['Funnel.conversions'], |
| 87 | + }, [ |
| 88 | + { funnel__conversions: '7' }, |
| 89 | + ])); |
| 90 | + }); |
| 91 | +}); |
0 commit comments