Created
February 19, 2026 05:44
-
-
Save musketyr/c750f00f331070ae7d3e9bab832047d8 to your computer and use it in GitHub Desktop.
Spock to JUnit 5 Migration Diff
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Spock → JUnit 5 Migration: GoogleAnalyticsRequestUtilsSpec</title> | |
| <style> | |
| * { box-sizing: border-box; margin: 0; padding: 0; } | |
| body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; padding: 20px; line-height: 1.6; } | |
| h1 { text-align: center; margin-bottom: 20px; color: #333; } | |
| .section { background: white; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); overflow: hidden; } | |
| .section-header { background: #2d3748; color: white; padding: 12px 16px; cursor: pointer; display: flex; justify-content: space-between; align-items: center; } | |
| .section-header:hover { background: #4a5568; } | |
| .section-header h2 { font-size: 16px; font-weight: 600; } | |
| .section-header .toggle { font-size: 12px; } | |
| .section-content { display: block; } | |
| .section-content.collapsed { display: none; } | |
| .diff-container { display: grid; grid-template-columns: 1fr 1fr; } | |
| .diff-panel { padding: 16px; overflow-x: auto; } | |
| .diff-panel.left { background: #fff5f5; border-right: 1px solid #e2e8f0; } | |
| .diff-panel.right { background: #f0fff4; } | |
| .diff-panel h3 { font-size: 12px; text-transform: uppercase; color: #718096; margin-bottom: 12px; letter-spacing: 0.5px; } | |
| pre { font-family: 'SF Mono', Monaco, 'Courier New', monospace; font-size: 13px; white-space: pre-wrap; word-wrap: break-word; } | |
| .left pre { color: #c53030; } | |
| .right pre { color: #276749; } | |
| @media (max-width: 768px) { .diff-container { grid-template-columns: 1fr; } .diff-panel.left { border-right: none; border-bottom: 1px solid #e2e8f0; } } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>🦀 Spock → JUnit 5 Migration: GoogleAnalyticsRequestUtilsSpec</h1> | |
| <p style="text-align: center; color: #666; margin-bottom: 20px;">Story: <a href="https://app.shortcut.com/agorapulse/story/185893">sc185893</a> | PR: <a href="https://github.com/agorapulse/platform/pull/72990">#72990</a></p> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>📦 Imports</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>package agorapulse.roi.service.google.client.analytics.api | |
| import agorapulse.roi.core.models.Dashboard | |
| import agorapulse.roi.core.models.EventType | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.DimensionName | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.Filter | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.FilterExpression | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.FilterExpressionList | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.InListFilter | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.MetricName | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.Payload | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.StringFilter | |
| import spock.lang.Specification | |
| import java.time.LocalDate</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>package agorapulse.roi.service.google.client.analytics.api; | |
| import agorapulse.roi.core.models.Dashboard; | |
| import agorapulse.roi.core.models.EventType; | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.DimensionName; | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.Filter; | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.FilterExpression; | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.FilterExpressionList; | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.InListFilter; | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.MetricName; | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.Payload; | |
| import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiRequest.StringFilter; | |
| import org.junit.jupiter.api.Test; | |
| import java.time.LocalDate; | |
| import java.util.List; | |
| import static org.assertj.core.api.Assertions.assertThat;</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🏗️ Class & Fields</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre>class GoogleAnalyticsRequestUtilsSpec extends Specification { | |
| private static final List<String> CONVERSION_EVENT_NAMES = ['one', 'session_start'] | |
| </pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre>class GoogleAnalyticsRequestUtilsTest { | |
| private static final List<String> CONVERSION_EVENT_NAMES = List.of("one", "session_start"); | |
| </pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should get event filters - custom event</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should get event filters - custom event'() { | |
| given: | |
| EventType eventType = EventType.CUSTOM_EVENT | |
| Dashboard.Goal event = new Dashboard.Goal('test', 'test', false) | |
| when: | |
| List<DimensionFilter> filters = GoogleAnalyticsRequestUtils.getEventFilters(eventType, CONVERSION_EVENT_NAMES, event, []) | |
| then: | |
| filters == [ | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.EVENT_NAME) | |
| .dimensionMatchType(DimensionMatchType.EXACT) | |
| .value('test') | |
| .build() | |
| ] | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldGetEventFiltersForCustomEvent() { | |
| // given | |
| EventType eventType = EventType.CUSTOM_EVENT; | |
| Dashboard.Goal event = new Dashboard.Goal("test", "test", false); | |
| // when | |
| List<DimensionFilter> filters = GoogleAnalyticsRequestUtils.getEventFilters(eventType, CONVERSION_EVENT_NAMES, event, List.of()); | |
| // then | |
| assertThat(filters).containsExactly( | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.EVENT_NAME) | |
| .dimensionMatchType(DimensionMatchType.EXACT) | |
| .value("test") | |
| .build() | |
| ); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should get event filters - all conversion events</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should get event filters - all conversion events'() { | |
| given: | |
| EventType eventType = EventType.ALL_CONVERSION_EVENTS | |
| when: | |
| List<DimensionFilter> filters = GoogleAnalyticsRequestUtils.getEventFilters(eventType, CONVERSION_EVENT_NAMES, null, []) | |
| then: | |
| filters == [ | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.IS_CONVERSION_EVENT) | |
| .dimensionMatchType(DimensionMatchType.EXACT) | |
| .value('true') | |
| .build() | |
| ] | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldGetEventFiltersForAllConversionEvents() { | |
| // given | |
| EventType eventType = EventType.ALL_CONVERSION_EVENTS; | |
| // when | |
| List<DimensionFilter> filters = GoogleAnalyticsRequestUtils.getEventFilters(eventType, CONVERSION_EVENT_NAMES, null, List.of()); | |
| // then | |
| assertThat(filters).containsExactly( | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.IS_CONVERSION_EVENT) | |
| .dimensionMatchType(DimensionMatchType.EXACT) | |
| .value("true") | |
| .build() | |
| ); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should get event filters - all events</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should get event filters - all events'() { | |
| given: | |
| EventType eventType = EventType.ALL_EVENTS | |
| when: | |
| List<DimensionFilter> filters = GoogleAnalyticsRequestUtils.getEventFilters(eventType, CONVERSION_EVENT_NAMES, null, []) | |
| then: | |
| filters == [ | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.EVENT_NAME) | |
| .notExpressionEnabled(true) | |
| .dimensionMatchType(DimensionMatchType.IN_LIST) | |
| .values(['user_engagement']) | |
| .build() | |
| ] | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldGetEventFiltersForAllEvents() { | |
| // given | |
| EventType eventType = EventType.ALL_EVENTS; | |
| // when | |
| List<DimensionFilter> filters = GoogleAnalyticsRequestUtils.getEventFilters(eventType, CONVERSION_EVENT_NAMES, null, List.of()); | |
| // then | |
| assertThat(filters).containsExactly( | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.EVENT_NAME) | |
| .notExpressionEnabled(true) | |
| .dimensionMatchType(DimensionMatchType.IN_LIST) | |
| .values(List.of("user_engagement")) | |
| .build() | |
| ); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should get event filters - all events except excluded events</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should get event filters - all events except excluded events'() { | |
| given: | |
| EventType eventType = EventType.ALL_EVENTS | |
| when: | |
| List<DimensionFilter> filters = GoogleAnalyticsRequestUtils.getEventFilters(eventType, CONVERSION_EVENT_NAMES, null, ['purchase']) | |
| then: | |
| filters == [ | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.EVENT_NAME) | |
| .notExpressionEnabled(true) | |
| .dimensionMatchType(DimensionMatchType.IN_LIST) | |
| .values(['user_engagement', 'purchase']) | |
| .build() | |
| ] | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldGetEventFiltersForAllEventsExceptExcludedEvents() { | |
| // given | |
| EventType eventType = EventType.ALL_EVENTS; | |
| // when | |
| List<DimensionFilter> filters = GoogleAnalyticsRequestUtils.getEventFilters(eventType, CONVERSION_EVENT_NAMES, null, List.of("purchase")); | |
| // then | |
| assertThat(filters).containsExactly( | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.EVENT_NAME) | |
| .notExpressionEnabled(true) | |
| .dimensionMatchType(DimensionMatchType.IN_LIST) | |
| .values(List.of("user_engagement", "purchase")) | |
| .build() | |
| ); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should get event filters - purchase event</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should get event filters - purchase event'() { | |
| given: | |
| EventType eventType = EventType.PURCHASE | |
| when: | |
| List<DimensionFilter> filters = GoogleAnalyticsRequestUtils.getEventFilters(eventType, CONVERSION_EVENT_NAMES, null, []) | |
| then: | |
| filters == [ | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.EVENT_NAME) | |
| .dimensionMatchType(DimensionMatchType.EXACT) | |
| .value('purchase') | |
| .build() | |
| ] | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldGetEventFiltersForPurchaseEvent() { | |
| // given | |
| EventType eventType = EventType.PURCHASE; | |
| // when | |
| List<DimensionFilter> filters = GoogleAnalyticsRequestUtils.getEventFilters(eventType, CONVERSION_EVENT_NAMES, null, List.of()); | |
| // then | |
| assertThat(filters).containsExactly( | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.EVENT_NAME) | |
| .dimensionMatchType(DimensionMatchType.EXACT) | |
| .value("purchase") | |
| .build() | |
| ); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should initialize events request</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should initialize events request'() { | |
| given: | |
| LocalDate startDate = LocalDate.parse('2023-01-01') | |
| LocalDate endDate = LocalDate.parse('2023-01-31') | |
| String accessToken = 'testAccessToken' | |
| String dashboardId = 'test' | |
| List<DimensionFilter> filters = [ | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.EVENT_NAME) | |
| .dimensionMatchType(DimensionMatchType.EXACT) | |
| .value('purchase') | |
| .build()] | |
| when: | |
| Ga4InsightsApiRequest request = GoogleAnalyticsRequestUtils.initEventsRequest(startDate, endDate, accessToken, dashboardId, filters, null) | |
| then: | |
| request.accessToken == accessToken | |
| request.propertyId == 'properties/' + dashboardId | |
| request.payload.dateRanges.first().startDate == startDate | |
| request.payload.dateRanges.first().endDate == endDate | |
| request.payload.dimensionFilter == FilterExpression.builder() | |
| .andGroup(new FilterExpressionList([ | |
| FilterExpression.builder() | |
| .filter(Filter.builder() | |
| .fieldName('eventName') | |
| .stringFilter(new StringFilter('EXACT', 'purchase')) | |
| .build()) | |
| .build()])) | |
| .build() | |
| request.payload.keepEmptyRows | |
| request.payload.limit == GoogleAnalyticsRequestUtils.DEFAULT_RESULT_LIMIT | |
| request.payload.metrics.size() == 4 | |
| request.payload.metrics.containsAll([ | |
| new MetricName(MetricType.CONVERSION_GOAL_COMPLETIONS.ga4Code), | |
| new MetricName(MetricType.GENERATED_REVENUE_GOAL_VALUE.ga4Code), | |
| new MetricName(MetricType.GENERATED_REVENUE_TRANSACTIONS.ga4Code), | |
| ]) | |
| request.payload.metricAggregations.first() == 'TOTAL' | |
| request.payload.offset == 0 | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldInitializeEventsRequest() { | |
| // given | |
| LocalDate startDate = LocalDate.parse("2023-01-01"); | |
| LocalDate endDate = LocalDate.parse("2023-01-31"); | |
| String accessToken = "testAccessToken"; | |
| String dashboardId = "test"; | |
| List<DimensionFilter> filters = List.of( | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.EVENT_NAME) | |
| .dimensionMatchType(DimensionMatchType.EXACT) | |
| .value("purchase") | |
| .build() | |
| ); | |
| // when | |
| Ga4InsightsApiRequest request = GoogleAnalyticsRequestUtils.initEventsRequest(startDate, endDate, accessToken, dashboardId, filters, null); | |
| // then | |
| assertThat(request.getAccessToken()).isEqualTo(accessToken); | |
| assertThat(request.getPropertyId()).isEqualTo("properties/" + dashboardId); | |
| assertThat(request.getPayload().getDateRanges().get(0).getStartDate()).isEqualTo(startDate); | |
| assertThat(request.getPayload().getDateRanges().get(0).getEndDate()).isEqualTo(endDate); | |
| assertThat(request.getPayload().getDimensionFilter()).isEqualTo( | |
| FilterExpression.builder() | |
| .andGroup(new FilterExpressionList(List.of( | |
| FilterExpression.builder() | |
| .filter(Filter.builder() | |
| .fieldName("eventName") | |
| .stringFilter(new StringFilter("EXACT", "purchase")) | |
| .build()) | |
| .build() | |
| ))) | |
| .build() | |
| ); | |
| assertThat(request.getPayload().getKeepEmptyRows()).isTrue(); | |
| assertThat(request.getPayload().getLimit()).isEqualTo(GoogleAnalyticsRequestUtils.DEFAULT_RESULT_LIMIT); | |
| assertThat(request.getPayload().getMetrics()).hasSize(4); | |
| assertThat(request.getPayload().getMetrics()).contains( | |
| new MetricName(MetricType.CONVERSION_GOAL_COMPLETIONS.getGa4Code()), | |
| new MetricName(MetricType.GENERATED_REVENUE_GOAL_VALUE.getGa4Code()), | |
| new MetricName(MetricType.GENERATED_REVENUE_TRANSACTIONS.getGa4Code()) | |
| ); | |
| assertThat(request.getPayload().getMetricAggregations().get(0)).isEqualTo("TOTAL"); | |
| assertThat(request.getPayload().getOffset()).isEqualTo(0); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should initialize Visitor request</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should initialize Visitor request'() { | |
| given: | |
| LocalDate startDate = LocalDate.parse('2023-01-01') | |
| LocalDate endDate = LocalDate.parse('2023-01-31') | |
| String accessToken = 'testAccessToken' | |
| String dashboardId = 'test' | |
| when: | |
| Ga4InsightsApiRequest request = GoogleAnalyticsRequestUtils.initVisitorRequest(startDate, endDate, accessToken, dashboardId, [], null) | |
| then: | |
| request.accessToken == accessToken | |
| request.propertyId == 'properties/' + dashboardId | |
| request.payload.dateRanges.first().startDate == startDate | |
| request.payload.dateRanges.first().endDate == endDate | |
| request.payload.dimensionFilter == FilterExpression.builder().andGroup(new FilterExpressionList([])).build() | |
| request.payload.keepEmptyRows | |
| request.payload.limit == GoogleAnalyticsRequestUtils.DEFAULT_RESULT_LIMIT | |
| request.payload.metrics.size() == 1 | |
| request.payload.metrics == [new MetricName(MetricType.VISITOR.ga4Code)] | |
| request.payload.metricAggregations.first() == 'TOTAL' | |
| request.payload.offset == 0 | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldInitializeVisitorRequest() { | |
| // given | |
| LocalDate startDate = LocalDate.parse("2023-01-01"); | |
| LocalDate endDate = LocalDate.parse("2023-01-31"); | |
| String accessToken = "testAccessToken"; | |
| String dashboardId = "test"; | |
| // when | |
| Ga4InsightsApiRequest request = GoogleAnalyticsRequestUtils.initVisitorRequest(startDate, endDate, accessToken, dashboardId, List.of(), null); | |
| // then | |
| assertThat(request.getAccessToken()).isEqualTo(accessToken); | |
| assertThat(request.getPropertyId()).isEqualTo("properties/" + dashboardId); | |
| assertThat(request.getPayload().getDateRanges().get(0).getStartDate()).isEqualTo(startDate); | |
| assertThat(request.getPayload().getDateRanges().get(0).getEndDate()).isEqualTo(endDate); | |
| assertThat(request.getPayload().getDimensionFilter()).isEqualTo( | |
| FilterExpression.builder().andGroup(new FilterExpressionList(List.of())).build() | |
| ); | |
| assertThat(request.getPayload().getKeepEmptyRows()).isTrue(); | |
| assertThat(request.getPayload().getLimit()).isEqualTo(GoogleAnalyticsRequestUtils.DEFAULT_RESULT_LIMIT); | |
| assertThat(request.getPayload().getMetrics()).hasSize(1); | |
| assertThat(request.getPayload().getMetrics()).containsExactly(new MetricName(MetricType.VISITOR.getGa4Code())); | |
| assertThat(request.getPayload().getMetricAggregations().get(0)).isEqualTo("TOTAL"); | |
| assertThat(request.getPayload().getOffset()).isEqualTo(0); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should initialize Events request - complex filters</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should initialize Events request - complex filters'() { | |
| given: | |
| LocalDate startDate = LocalDate.parse('2023-01-01') | |
| LocalDate endDate = LocalDate.parse('2023-01-31') | |
| String accessToken = 'testAccessToken' | |
| String dashboardId = 'test' | |
| List<DimensionFilter> filters = [ | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.EVENT_NAME) | |
| .notExpressionEnabled(true) | |
| .dimensionMatchType(DimensionMatchType.IN_LIST) | |
| .values(['session_start', 'user_engagement']) | |
| .build(), | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.CHANNEL_GROUPING) | |
| .dimensionMatchType(DimensionMatchType.EXACT) | |
| .value('Organic Social') | |
| .build(), | |
| ] | |
| when: | |
| Ga4InsightsApiRequest request = GoogleAnalyticsRequestUtils.initEventsRequest(startDate, endDate, accessToken, dashboardId, filters, null) | |
| then: | |
| request.payload.dimensionFilter == FilterExpression.builder() | |
| .andGroup(new FilterExpressionList([ | |
| FilterExpression.builder() | |
| .notExpression(FilterExpression.builder() | |
| .filter(Filter.builder() | |
| .fieldName('eventName') | |
| .inListFilter(new InListFilter(['session_start', 'user_engagement'])) | |
| .build()) | |
| .build()) | |
| .build(), | |
| FilterExpression.builder() | |
| .filter(Filter.builder() | |
| .fieldName('sessionDefaultChannelGroup') | |
| .stringFilter(new StringFilter('EXACT', 'Organic Social')) | |
| .build()) | |
| .build(), | |
| ])) | |
| .build() | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldInitializeEventsRequestWithComplexFilters() { | |
| // given | |
| LocalDate startDate = LocalDate.parse("2023-01-01"); | |
| LocalDate endDate = LocalDate.parse("2023-01-31"); | |
| String accessToken = "testAccessToken"; | |
| String dashboardId = "test"; | |
| List<DimensionFilter> filters = List.of( | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.EVENT_NAME) | |
| .notExpressionEnabled(true) | |
| .dimensionMatchType(DimensionMatchType.IN_LIST) | |
| .values(List.of("session_start", "user_engagement")) | |
| .build(), | |
| DimensionFilter.builder() | |
| .dimensionType(DimensionType.CHANNEL_GROUPING) | |
| .dimensionMatchType(DimensionMatchType.EXACT) | |
| .value("Organic Social") | |
| .build() | |
| ); | |
| // when | |
| Ga4InsightsApiRequest request = GoogleAnalyticsRequestUtils.initEventsRequest(startDate, endDate, accessToken, dashboardId, filters, null); | |
| // then | |
| assertThat(request.getPayload().getDimensionFilter()).isEqualTo( | |
| FilterExpression.builder() | |
| .andGroup(new FilterExpressionList(List.of( | |
| FilterExpression.builder() | |
| .notExpression(FilterExpression.builder() | |
| .filter(Filter.builder() | |
| .fieldName("eventName") | |
| .inListFilter(new InListFilter(List.of("session_start", "user_engagement"))) | |
| .build()) | |
| .build()) | |
| .build(), | |
| FilterExpression.builder() | |
| .filter(Filter.builder() | |
| .fieldName("sessionDefaultChannelGroup") | |
| .stringFilter(new StringFilter("EXACT", "Organic Social")) | |
| .build()) | |
| .build() | |
| ))) | |
| .build() | |
| ); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should add orderBy to request with transactions conversion - visitors</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should add orderBy to request with transactions conversion - visitors'() { | |
| given: | |
| Payload payload = Payload.builder().metrics([new MetricName(MetricType.VISITOR.ga4Code)]).build() | |
| when: | |
| GoogleAnalyticsRequestUtils.addOrderBy(payload, EventType.PURCHASE, MetricType.VISITOR.ga4Code, true) | |
| then: | |
| payload.orderBys.size() == 1 | |
| payload.orderBys[0].metric.metricName == MetricType.VISITOR.ga4Code | |
| payload.orderBys[0].desc | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldAddOrderByToRequestWithTransactionsConversionForVisitors() { | |
| // given | |
| Payload payload = Payload.builder().metrics(List.of(new MetricName(MetricType.VISITOR.getGa4Code()))).build(); | |
| // when | |
| GoogleAnalyticsRequestUtils.addOrderBy(payload, EventType.PURCHASE, MetricType.VISITOR.getGa4Code(), true); | |
| // then | |
| assertThat(payload.getOrderBys()).hasSize(1); | |
| assertThat(payload.getOrderBys().get(0).getMetric().getMetricName()).isEqualTo(MetricType.VISITOR.getGa4Code()); | |
| assertThat(payload.getOrderBys().get(0).getDesc()).isTrue(); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should add orderBy to request with transactions conversion - events</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should add orderBy to request with transactions conversion - events'() { | |
| given: | |
| Payload payload = Payload.builder() | |
| .metrics(MetricType.values().findAll { metric -> metric != MetricType.VISITOR }.collect { metric -> new MetricName(metric.ga4Code) }) | |
| .build() | |
| when: | |
| GoogleAnalyticsRequestUtils.addOrderBy(payload, EventType.PURCHASE, MetricType.VISITOR.ga4Code, true) | |
| then: | |
| payload.orderBys.size() == 2 | |
| payload.orderBys[0].metric.metricName == MetricType.CONVERSION_TRANSACTIONS.ga4Code | |
| payload.orderBys[0].desc | |
| payload.orderBys[1].metric.metricName == MetricType.GENERATED_REVENUE_TRANSACTIONS.ga4Code | |
| payload.orderBys[1].desc | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldAddOrderByToRequestWithTransactionsConversionForEvents() { | |
| // given | |
| List<MetricName> metrics = java.util.Arrays.stream(MetricType.values()) | |
| .filter(metric -> metric != MetricType.VISITOR) | |
| .map(metric -> new MetricName(metric.getGa4Code())) | |
| .toList(); | |
| Payload payload = Payload.builder().metrics(metrics).build(); | |
| // when | |
| GoogleAnalyticsRequestUtils.addOrderBy(payload, EventType.PURCHASE, MetricType.VISITOR.getGa4Code(), true); | |
| // then | |
| assertThat(payload.getOrderBys()).hasSize(2); | |
| assertThat(payload.getOrderBys().get(0).getMetric().getMetricName()).isEqualTo(MetricType.CONVERSION_TRANSACTIONS.getGa4Code()); | |
| assertThat(payload.getOrderBys().get(0).getDesc()).isTrue(); | |
| assertThat(payload.getOrderBys().get(1).getMetric().getMetricName()).isEqualTo(MetricType.GENERATED_REVENUE_TRANSACTIONS.getGa4Code()); | |
| assertThat(payload.getOrderBys().get(1).getDesc()).isTrue(); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should add orderBy to request with goal conversion - visitors</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should add orderBy to request with goal conversion - visitors'() { | |
| given: | |
| Payload payload = Payload.builder().metrics([new MetricName(MetricType.VISITOR.ga4Code)]).build() | |
| when: | |
| GoogleAnalyticsRequestUtils.addOrderBy(payload, EventType.ALL_EVENTS, MetricType.CONVERSION_GOAL_COMPLETIONS.ga4Code, false) | |
| then: | |
| payload.orderBys.size() == 1 | |
| payload.orderBys[0].metric.metricName == MetricType.VISITOR.ga4Code | |
| !payload.orderBys[0].desc | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldAddOrderByToRequestWithGoalConversionForVisitors() { | |
| // given | |
| Payload payload = Payload.builder().metrics(List.of(new MetricName(MetricType.VISITOR.getGa4Code()))).build(); | |
| // when | |
| GoogleAnalyticsRequestUtils.addOrderBy(payload, EventType.ALL_EVENTS, MetricType.CONVERSION_GOAL_COMPLETIONS.getGa4Code(), false); | |
| // then | |
| assertThat(payload.getOrderBys()).hasSize(1); | |
| assertThat(payload.getOrderBys().get(0).getMetric().getMetricName()).isEqualTo(MetricType.VISITOR.getGa4Code()); | |
| assertThat(payload.getOrderBys().get(0).getDesc()).isFalse(); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should add orderBy to request with goal conversion - events</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should add orderBy to request with goal conversion - events'() { | |
| given: | |
| Payload payload = Payload.builder() | |
| .metrics(MetricType.values().findAll { metric -> metric != MetricType.VISITOR }.collect { metric -> new MetricName(metric.ga4Code) }) | |
| .build() | |
| when: | |
| GoogleAnalyticsRequestUtils.addOrderBy(payload, EventType.ALL_EVENTS, MetricType.CONVERSION_GOAL_COMPLETIONS.ga4Code, false) | |
| then: | |
| payload.orderBys.size() == 2 | |
| payload.orderBys[0].metric.metricName == MetricType.CONVERSION_GOAL_COMPLETIONS.ga4Code | |
| !payload.orderBys[0].desc | |
| payload.orderBys[1].metric.metricName == MetricType.GENERATED_REVENUE_GOAL_VALUE.ga4Code | |
| !payload.orderBys[1].desc | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldAddOrderByToRequestWithGoalConversionForEvents() { | |
| // given | |
| List<MetricName> metrics = java.util.Arrays.stream(MetricType.values()) | |
| .filter(metric -> metric != MetricType.VISITOR) | |
| .map(metric -> new MetricName(metric.getGa4Code())) | |
| .toList(); | |
| Payload payload = Payload.builder().metrics(metrics).build(); | |
| // when | |
| GoogleAnalyticsRequestUtils.addOrderBy(payload, EventType.ALL_EVENTS, MetricType.CONVERSION_GOAL_COMPLETIONS.getGa4Code(), false); | |
| // then | |
| assertThat(payload.getOrderBys()).hasSize(2); | |
| assertThat(payload.getOrderBys().get(0).getMetric().getMetricName()).isEqualTo(MetricType.CONVERSION_GOAL_COMPLETIONS.getGa4Code()); | |
| assertThat(payload.getOrderBys().get(0).getDesc()).isFalse(); | |
| assertThat(payload.getOrderBys().get(1).getMetric().getMetricName()).isEqualTo(MetricType.GENERATED_REVENUE_GOAL_VALUE.getGa4Code()); | |
| assertThat(payload.getOrderBys().get(1).getDesc()).isFalse(); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should finalize request with dimensions and dimension filters</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should finalize request with dimensions and dimension filters'() { | |
| given: | |
| FilterExpression filter = FilterExpression.builder() | |
| .filter(Filter.builder() | |
| .fieldName(DimensionType.EVENT_NAME.ga4Code) | |
| .stringFilter(new StringFilter(DimensionMatchType.EXACT.name(), 'purchase')) | |
| .build()) | |
| .build() | |
| FilterExpression newAddedFilter = FilterExpression.builder() | |
| .filter(Filter.builder() | |
| .fieldName(DimensionType.CHANNEL_GROUPING.ga4Code) | |
| .stringFilter(new StringFilter(DimensionMatchType.EXACT.name(), 'Organic Social')) | |
| .build()) | |
| .build() | |
| Payload payload = Payload.builder().dimensionFilter(FilterExpression.builder().andGroup(new FilterExpressionList([filter])).build()).build() | |
| when: | |
| GoogleAnalyticsRequestUtils.finalizeRequest( | |
| payload, | |
| [DimensionType.CHANNEL_GROUPING, DimensionType.DATE], | |
| [DimensionFilter.builder() | |
| .dimensionType(DimensionType.CHANNEL_GROUPING) | |
| .dimensionMatchType(DimensionMatchType.EXACT) | |
| .value('Organic Social') | |
| .build()]) | |
| then: | |
| payload.dimensions.size() == 2 | |
| payload.dimensions.containsAll([ | |
| new DimensionName(DimensionType.CHANNEL_GROUPING.ga4Code), | |
| new DimensionName(DimensionType.DATE.ga4Code)]) | |
| payload.dimensionFilter.andGroup.expressions.size() == 2 | |
| payload.dimensionFilter.andGroup.expressions.containsAll(filter, newAddedFilter) | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldFinalizeRequestWithDimensionsAndDimensionFilters() { | |
| // given | |
| FilterExpression filter = FilterExpression.builder() | |
| .filter(Filter.builder() | |
| .fieldName(DimensionType.EVENT_NAME.getGa4Code()) | |
| .stringFilter(new StringFilter(DimensionMatchType.EXACT.name(), "purchase")) | |
| .build()) | |
| .build(); | |
| FilterExpression newAddedFilter = FilterExpression.builder() | |
| .filter(Filter.builder() | |
| .fieldName(DimensionType.CHANNEL_GROUPING.getGa4Code()) | |
| .stringFilter(new StringFilter(DimensionMatchType.EXACT.name(), "Organic Social")) | |
| .build()) | |
| .build(); | |
| Payload payload = Payload.builder() | |
| .dimensionFilter(FilterExpression.builder().andGroup(new FilterExpressionList(List.of(filter))).build()) | |
| .build(); | |
| // when | |
| GoogleAnalyticsRequestUtils.finalizeRequest( | |
| payload, | |
| List.of(DimensionType.CHANNEL_GROUPING, DimensionType.DATE), | |
| List.of(DimensionFilter.builder() | |
| .dimensionType(DimensionType.CHANNEL_GROUPING) | |
| .dimensionMatchType(DimensionMatchType.EXACT) | |
| .value("Organic Social") | |
| .build()) | |
| ); | |
| // then | |
| assertThat(payload.getDimensions()).hasSize(2); | |
| assertThat(payload.getDimensions()).contains( | |
| new DimensionName(DimensionType.CHANNEL_GROUPING.getGa4Code()), | |
| new DimensionName(DimensionType.DATE.getGa4Code()) | |
| ); | |
| assertThat(payload.getDimensionFilter().getAndGroup().getExpressions()).hasSize(2); | |
| assertThat(payload.getDimensionFilter().getAndGroup().getExpressions()).contains(filter, newAddedFilter); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <div class="section-header" onclick="toggleSection(this)"> | |
| <h2>🧪 Should finalize request with dimensions and no filters</h2> | |
| <span class="toggle">▼</span> | |
| </div> | |
| <div class="section-content"> | |
| <div class="diff-container"> | |
| <div class="diff-panel left"> | |
| <h3>Spock (Groovy)</h3> | |
| <pre> void 'Should finalize request with dimensions and no filters'() { | |
| given: | |
| Payload payload = Payload.builder().dimensionFilter(FilterExpression.builder().andGroup(new FilterExpressionList([])).build()).build() | |
| when: | |
| GoogleAnalyticsRequestUtils.finalizeRequest( | |
| payload, | |
| [DimensionType.CHANNEL_GROUPING, DimensionType.DATE], | |
| [] | |
| ) | |
| then: | |
| payload.dimensions.size() == 2 | |
| payload.dimensions.containsAll([ | |
| new DimensionName(DimensionType.CHANNEL_GROUPING.ga4Code), | |
| new DimensionName(DimensionType.DATE.ga4Code)]) | |
| payload.dimensionFilter == null | |
| }</pre> | |
| </div> | |
| <div class="diff-panel right"> | |
| <h3>JUnit 5 (Java)</h3> | |
| <pre> @Test | |
| void shouldFinalizeRequestWithDimensionsAndNoFilters() { | |
| // given | |
| Payload payload = Payload.builder() | |
| .dimensionFilter(FilterExpression.builder().andGroup(new FilterExpressionList(List.of())).build()) | |
| .build(); | |
| // when | |
| GoogleAnalyticsRequestUtils.finalizeRequest( | |
| payload, | |
| List.of(DimensionType.CHANNEL_GROUPING, DimensionType.DATE), | |
| List.of() | |
| ); | |
| // then | |
| assertThat(payload.getDimensions()).hasSize(2); | |
| assertThat(payload.getDimensions()).contains( | |
| new DimensionName(DimensionType.CHANNEL_GROUPING.getGa4Code()), | |
| new DimensionName(DimensionType.DATE.getGa4Code()) | |
| ); | |
| assertThat(payload.getDimensionFilter()).isNull(); | |
| }</pre> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| function toggleSection(header) { | |
| const content = header.nextElementSibling; | |
| const toggle = header.querySelector('.toggle'); | |
| content.classList.toggle('collapsed'); | |
| toggle.textContent = content.classList.contains('collapsed') ? '▶' : '▼'; | |
| } | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment