Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save musketyr/2ed7bb737712b42ce7636946b61d8734 to your computer and use it in GitHub Desktop.

Select an option

Save musketyr/2ed7bb737712b42ce7636946b61d8734 to your computer and use it in GitHub Desktop.
Spock to JUnit 5 Migration: GoogleAnalyticsResponseUtilsSpec (sc185894)
<!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: GoogleAnalyticsResponseUtilsSpec</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; }
.summary { background: #c6f6d5; border-left: 4px solid #38a169; padding: 12px 16px; margin: 0; }
.summary p { color: #276749; font-size: 14px; }
.summary strong { color: #22543d; }
@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: GoogleAnalyticsResponseUtilsSpec</h1>
<p style="text-align: center; color: #666; margin-bottom: 20px;">Story: <a href="https://app.shortcut.com/agorapulse/story/185894">sc185894</a> | PR: <a href="https://github.com/agorapulse/platform/pull/73543">#73543</a></p>
<!-- Section: Imports -->
<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.service.google.client.analytics.api.Ga4InsightsApiResponse.Header
import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiResponse.Row
import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiResponse.Value
import spock.lang.Specification</pre>
</div>
<div class="diff-panel right">
<h3>JUnit 5 (Java)</h3>
<pre>package agorapulse.roi.service.google.client.analytics.api;
import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiResponse.Header;
import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiResponse.Row;
import agorapulse.roi.service.google.client.analytics.api.Ga4InsightsApiResponse.Value;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;</pre>
</div>
</div>
<div class="summary">
<p><strong>Changes:</strong> Replaced Spock Specification import with JUnit 5 @Test and AssertJ assertions. Added Java utility imports (List, Map).</p>
</div>
</div>
</div>
<!-- Section: Class & Fields -->
<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 GoogleAnalyticsResponseUtilsSpec extends Specification {
}</pre>
</div>
<div class="diff-panel right">
<h3>JUnit 5 (Java)</h3>
<pre>class GoogleAnalyticsResponseUtilsTest {
private Row createRow(List&lt;String&gt; dimensionValues, List&lt;String&gt; metricValues) {
Row row = new Row();
row.setDimensionValues(dimensionValues.stream().map(Value::new).toList());
row.setMetricValues(metricValues.stream().map(Value::new).toList());
return row;
}
private Row createRowWithMetricsOnly(List&lt;String&gt; metricValues) {
Row row = new Row();
row.setMetricValues(metricValues.stream().map(Value::new).toList());
return row;
}
}</pre>
</div>
</div>
<div class="summary">
<p><strong>Changes:</strong> Removed Specification inheritance. Added helper methods createRow() and createRowWithMetricsOnly() to replace Groovy's concise object construction syntax.</p>
</div>
</div>
</div>
<!-- Section: Test 1 -->
<div class="section">
<div class="section-header" onclick="toggleSection(this)">
<h2>🧪 Should map response headers with values</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 map response headers with values'() {
given:
Ga4InsightsApiResponse eventsResponse = new Ga4InsightsApiResponse(
dimensionHeaders: [new Header(name: 'date')],
metricHeaders: [new Header(name: 'eventValue'), new Header(name: 'eventCount'), new Header(name: 'transactions'), new Header(name: 'purchaseRevenue')],
rows: [
new Row(dimensionValues: [new Value(value: '20230101')], metricValues: [new Value(value: '2.0'), new Value(value: '7'), new Value(value: '17'), new Value(value: '29.0')]),
]
)
when:
Map&lt;String, String&gt; response = GoogleAnalyticsResponseUtils.mapHeadersWithValues(eventsResponse.metricHeaders, eventsResponse.rows.get(0).metricValues)
then:
response == [eventValue: '2.0', eventCount: '7', transactions: '17', purchaseRevenue: '29.0']
}</pre>
</div>
<div class="diff-panel right">
<h3>JUnit 5 (Java)</h3>
<pre>@Test
void shouldMapResponseHeadersWithValues() {
// given
Ga4InsightsApiResponse eventsResponse = new Ga4InsightsApiResponse();
eventsResponse.setDimensionHeaders(List.of(new Header("date")));
eventsResponse.setMetricHeaders(List.of(
new Header("eventValue"),
new Header("eventCount"),
new Header("transactions"),
new Header("purchaseRevenue")
));
eventsResponse.setRows(List.of(
createRow(List.of("20230101"), List.of("2.0", "7", "17", "29.0"))
));
// when
Map&lt;String, String&gt; response = GoogleAnalyticsResponseUtils.mapHeadersWithValues(
eventsResponse.getMetricHeaders(),
eventsResponse.getRows().get(0).getMetricValues()
);
// then
assertThat(response).containsExactlyInAnyOrderEntriesOf(Map.of(
"eventValue", "2.0",
"eventCount", "7",
"transactions", "17",
"purchaseRevenue", "29.0"
));
}</pre>
</div>
</div>
<div class="summary">
<p><strong>Changes:</strong> Added @Test annotation. Replaced Groovy map constructor with setter calls and helper method. Replaced Spock == with AssertJ containsExactlyInAnyOrderEntriesOf().</p>
</div>
</div>
</div>
<!-- Section: Test 2 -->
<div class="section">
<div class="section-header" onclick="toggleSection(this)">
<h2>🧪 Should map response headers with values - headers size greater than values size</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 map response headers with values - headers size greater than values size'() {
given:
Ga4InsightsApiResponse eventsResponse = new Ga4InsightsApiResponse(
dimensionHeaders: [new Header(name: 'date')],
metricHeaders: [new Header(name: 'eventValue'), new Header(name: 'eventCount'), new Header(name: 'transactions'), new Header(name: 'purchaseRevenue')],
rows: [
new Row(dimensionValues: [new Value(value: '20230101')], metricValues: [new Value(value: '2.0')]),
]
)
when:
Map&lt;String, String&gt; response = GoogleAnalyticsResponseUtils.mapHeadersWithValues(eventsResponse.metricHeaders, eventsResponse.rows.get(0).metricValues)
then:
response == [eventValue: '2.0', eventCount: '0', transactions: '0', purchaseRevenue: '0.0']
}</pre>
</div>
<div class="diff-panel right">
<h3>JUnit 5 (Java)</h3>
<pre>@Test
void shouldMapResponseHeadersWithValuesWhenHeadersSizeGreaterThanValuesSize() {
// given
Ga4InsightsApiResponse eventsResponse = new Ga4InsightsApiResponse();
eventsResponse.setDimensionHeaders(List.of(new Header("date")));
eventsResponse.setMetricHeaders(List.of(
new Header("eventValue"),
new Header("eventCount"),
new Header("transactions"),
new Header("purchaseRevenue")
));
eventsResponse.setRows(List.of(
createRow(List.of("20230101"), List.of("2.0"))
));
// when
Map&lt;String, String&gt; response = GoogleAnalyticsResponseUtils.mapHeadersWithValues(
eventsResponse.getMetricHeaders(),
eventsResponse.getRows().get(0).getMetricValues()
);
// then
assertThat(response).containsExactlyInAnyOrderEntriesOf(Map.of(
"eventValue", "2.0",
"eventCount", "0",
"transactions", "0",
"purchaseRevenue", "0.0"
));
}</pre>
</div>
</div>
<div class="summary">
<p><strong>Changes:</strong> Added @Test annotation. Converted test name to camelCase. Replaced Groovy construction with Java setters and helper method.</p>
</div>
</div>
</div>
<!-- Section: Test 3 -->
<div class="section">
<div class="section-header" onclick="toggleSection(this)">
<h2>🧪 Should map response headers with values - values size greater than headers size</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 map response headers with values - values size greater than headers size'() {
given:
Ga4InsightsApiResponse eventsResponse = new Ga4InsightsApiResponse(
dimensionHeaders: [new Header(name: 'date')],
metricHeaders: [new Header(name: 'eventValue'), new Header(name: 'eventCount')],
rows: [
new Row(dimensionValues: [new Value(value: '20230101')], metricValues: [new Value(value: '2.0'), new Value(value: '7'), new Value(value: '17'), new Value(value: '29.0')]),
]
)
when:
GoogleAnalyticsResponseUtils.mapHeadersWithValues(eventsResponse.metricHeaders, eventsResponse.rows.get(0).metricValues)
then:
Exception e = thrown(IllegalArgumentException)
e.message == "Headers should have a size greater or equals than values, header size = 2, values size = 4"
}</pre>
</div>
<div class="diff-panel right">
<h3>JUnit 5 (Java)</h3>
<pre>@Test
void shouldThrowExceptionWhenValuesSizeGreaterThanHeadersSize() {
// given
Ga4InsightsApiResponse eventsResponse = new Ga4InsightsApiResponse();
eventsResponse.setDimensionHeaders(List.of(new Header("date")));
eventsResponse.setMetricHeaders(List.of(
new Header("eventValue"),
new Header("eventCount")
));
eventsResponse.setRows(List.of(
createRow(List.of("20230101"), List.of("2.0", "7", "17", "29.0"))
));
// when/then
assertThatThrownBy(() -&gt; GoogleAnalyticsResponseUtils.mapHeadersWithValues(
eventsResponse.getMetricHeaders(),
eventsResponse.getRows().get(0).getMetricValues()
))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Headers should have a size greater or equals than values, header size = 2, values size = 4");
}</pre>
</div>
</div>
<div class="summary">
<p><strong>Changes:</strong> Replaced Spock's thrown() with AssertJ's assertThatThrownBy(). Lambda captures the exception-throwing call. Chains isInstanceOf() and hasMessage() for verification.</p>
</div>
</div>
</div>
<!-- Section: Test 4 -->
<div class="section">
<div class="section-header" onclick="toggleSection(this)">
<h2>🧪 Should merge batch responses</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 merge batch responses'() {
given:
Ga4InsightsApiResponse visitorsResponse = new Ga4InsightsApiResponse(
dimensionHeaders: [new Header(name: 'date')],
metricHeaders: [new Header(name: 'totalUsers')],
rows: [
new Row(dimensionValues: [new Value(value: '20230101')], metricValues: [new Value(value: '10')]),
new Row(dimensionValues: [new Value(value: '20230102')], metricValues: [new Value(value: '13')]),
],
totals: [new Row(metricValues: [new Value(value: '15')])]
)
Ga4InsightsApiResponse eventsResponse = new Ga4InsightsApiResponse(
dimensionHeaders: [new Header(name: 'date'), new Header(name: 'eventName')],
metricHeaders: [new Header(name: 'eventValue'), new Header(name: 'eventCount'), new Header(name: 'transactions'), new Header(name: 'purchaseRevenue')],
rows: [
new Row(dimensionValues: [new Value(value: '20230101')], metricValues: [new Value(value: '2.0'), new Value(value: '7'), new Value(value: '17'), new Value(value: '29.0')]),
],
totals: [new Row(metricValues: [new Value(value: '2.0'), new Value(value: '7'), new Value(value: '17'), new Value(value: '29.0')])]
)
when:
Ga4InsightsApiResponse mergedResponse = GoogleAnalyticsResponseUtils.mergeBatchResponse(visitorsResponse, eventsResponse)
then:
mergedResponse.dimensionHeaders == [new Header(name: 'date')]
mergedResponse.metricHeaders == [new Header(name: 'totalUsers'), new Header(name: 'eventValue'), new Header(name: 'eventCount'), new Header(name: 'transactions'), new Header(name: 'purchaseRevenue')]
mergedResponse.rows == [
new Row(dimensionValues: [new Value(value: '20230101')], metricValues: [new Value(value: '10'), new Value(value: '2.0'), new Value(value: '7'), new Value(value: '17'), new Value(value: '29.0')]),
new Row(dimensionValues: [new Value(value: '20230102')], metricValues: [new Value(value: '13'), new Value(value: '0.0'), new Value(value: '0'), new Value(value: '0'), new Value(value: '0.0')]),
]
mergedResponse.totals == [
new Row(metricValues: [new Value(value: '15'), new Value(value: '2.0'), new Value(value: '7'), new Value(value: '17'), new Value(value: '29.0')])
]
}</pre>
</div>
<div class="diff-panel right">
<h3>JUnit 5 (Java)</h3>
<pre>@Test
void shouldMergeBatchResponses() {
// given
Ga4InsightsApiResponse visitorsResponse = new Ga4InsightsApiResponse();
visitorsResponse.setDimensionHeaders(List.of(new Header("date")));
visitorsResponse.setMetricHeaders(List.of(new Header("totalUsers")));
visitorsResponse.setRows(List.of(
createRow(List.of("20230101"), List.of("10")),
createRow(List.of("20230102"), List.of("13"))
));
visitorsResponse.setTotals(List.of(createRowWithMetricsOnly(List.of("15"))));
Ga4InsightsApiResponse eventsResponse = new Ga4InsightsApiResponse();
eventsResponse.setDimensionHeaders(List.of(new Header("date"), new Header("eventName")));
eventsResponse.setMetricHeaders(List.of(
new Header("eventValue"),
new Header("eventCount"),
new Header("transactions"),
new Header("purchaseRevenue")
));
eventsResponse.setRows(List.of(
createRow(List.of("20230101"), List.of("2.0", "7", "17", "29.0"))
));
eventsResponse.setTotals(List.of(createRowWithMetricsOnly(List.of("2.0", "7", "17", "29.0"))));
// when
Ga4InsightsApiResponse mergedResponse = GoogleAnalyticsResponseUtils.mergeBatchResponse(visitorsResponse, eventsResponse);
// then
assertThat(mergedResponse.getDimensionHeaders()).containsExactly(new Header("date"));
assertThat(mergedResponse.getMetricHeaders()).containsExactly(
new Header("totalUsers"),
new Header("eventValue"),
new Header("eventCount"),
new Header("transactions"),
new Header("purchaseRevenue")
);
assertThat(mergedResponse.getRows()).containsExactly(
createRow(List.of("20230101"), List.of("10", "2.0", "7", "17", "29.0")),
createRow(List.of("20230102"), List.of("13", "0.0", "0", "0", "0.0"))
);
assertThat(mergedResponse.getTotals()).containsExactly(
createRowWithMetricsOnly(List.of("15", "2.0", "7", "17", "29.0"))
);
}</pre>
</div>
</div>
<div class="summary">
<p><strong>Changes:</strong> Replaced Groovy property access with Java getters. Used helper methods for cleaner Row construction. Replaced Spock == with AssertJ containsExactly() for list assertions.</p>
</div>
</div>
</div>
<!-- Section: Test 5 -->
<div class="section">
<div class="section-header" onclick="toggleSection(this)">
<h2>🧪 Should merge batch responses - 0 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 merge batch responses - 0 event'() {
given:
Ga4InsightsApiResponse visitorsResponse = new Ga4InsightsApiResponse(
dimensionHeaders: [new Header(name: 'date')],
metricHeaders: [new Header(name: 'totalUsers')],
rows: [
new Row(dimensionValues: [new Value(value: '20230101')], metricValues: [new Value(value: '10')]),
new Row(dimensionValues: [new Value(value: '20230102')], metricValues: [new Value(value: '13')]),
],
totals: [new Row(metricValues: [new Value(value: '15')])]
)
Ga4InsightsApiResponse eventsResponse = new Ga4InsightsApiResponse(
dimensionHeaders: [new Header(name: 'date'), new Header(name: 'eventName')],
metricHeaders: [new Header(name: 'eventValue'), new Header(name: 'eventCount'), new Header(name: 'transactions'), new Header(name: 'purchaseRevenue')],
totals: [new Row()]
)
when:
Ga4InsightsApiResponse mergedResponse = GoogleAnalyticsResponseUtils.mergeBatchResponse(visitorsResponse, eventsResponse)
then:
mergedResponse.dimensionHeaders == [new Header(name: 'date')]
mergedResponse.metricHeaders == [new Header(name: 'totalUsers'), new Header(name: 'eventValue'), new Header(name: 'eventCount'), new Header(name: 'transactions'), new Header(name: 'purchaseRevenue')]
mergedResponse.rows == [
new Row(dimensionValues: [new Value(value: '20230101')], metricValues: [new Value(value: '10'), new Value(value: '0.0'), new Value(value: '0'), new Value(value: '0'), new Value(value: '0.0')]),
new Row(dimensionValues: [new Value(value: '20230102')], metricValues: [new Value(value: '13'), new Value(value: '0.0'), new Value(value: '0'), new Value(value: '0'), new Value(value: '0.0')]),
]
mergedResponse.totals == [
new Row(metricValues: [new Value(value: '15'), new Value(value: '0.0'), new Value(value: '0'), new Value(value: '0'), new Value(value: '0.0')])
]
}</pre>
</div>
<div class="diff-panel right">
<h3>JUnit 5 (Java)</h3>
<pre>@Test
void shouldMergeBatchResponsesWithZeroEvents() {
// given
Ga4InsightsApiResponse visitorsResponse = new Ga4InsightsApiResponse();
visitorsResponse.setDimensionHeaders(List.of(new Header("date")));
visitorsResponse.setMetricHeaders(List.of(new Header("totalUsers")));
visitorsResponse.setRows(List.of(
createRow(List.of("20230101"), List.of("10")),
createRow(List.of("20230102"), List.of("13"))
));
visitorsResponse.setTotals(List.of(createRowWithMetricsOnly(List.of("15"))));
Ga4InsightsApiResponse eventsResponse = new Ga4InsightsApiResponse();
eventsResponse.setDimensionHeaders(List.of(new Header("date"), new Header("eventName")));
eventsResponse.setMetricHeaders(List.of(
new Header("eventValue"),
new Header("eventCount"),
new Header("transactions"),
new Header("purchaseRevenue")
));
eventsResponse.setTotals(List.of(new Row()));
// when
Ga4InsightsApiResponse mergedResponse = GoogleAnalyticsResponseUtils.mergeBatchResponse(visitorsResponse, eventsResponse);
// then
assertThat(mergedResponse.getDimensionHeaders()).containsExactly(new Header("date"));
assertThat(mergedResponse.getMetricHeaders()).containsExactly(
new Header("totalUsers"),
new Header("eventValue"),
new Header("eventCount"),
new Header("transactions"),
new Header("purchaseRevenue")
);
assertThat(mergedResponse.getRows()).containsExactly(
createRow(List.of("20230101"), List.of("10", "0.0", "0", "0", "0.0")),
createRow(List.of("20230102"), List.of("13", "0.0", "0", "0", "0.0"))
);
assertThat(mergedResponse.getTotals()).containsExactly(
createRowWithMetricsOnly(List.of("15", "0.0", "0", "0", "0.0"))
);
}</pre>
</div>
</div>
<div class="summary">
<p><strong>Changes:</strong> Test name converted to camelCase (WithZeroEvents). Tests edge case where eventsResponse has no rows (only totals with empty Row). Uses AssertJ containsExactly() for assertions.</p>
</div>
</div>
</div>
<!-- Section: Test 6 -->
<div class="section">
<div class="section-header" onclick="toggleSection(this)">
<h2>🧪 Should merge batch responses - 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 merge batch responses - all events'() {
given:
Ga4InsightsApiResponse visitorsResponse = new Ga4InsightsApiResponse(
dimensionHeaders: [new Header(name: 'date')],
metricHeaders: [new Header(name: 'totalUsers')],
rows: [
new Row(dimensionValues: [new Value(value: '20230101')], metricValues: [new Value(value: '10')]),
new Row(dimensionValues: [new Value(value: '20230102')], metricValues: [new Value(value: '13')]),
],
totals: [new Row(metricValues: [new Value(value: '15')])]
)
Ga4InsightsApiResponse eventsResponse = new Ga4InsightsApiResponse(
dimensionHeaders: [new Header(name: 'date'), new Header(name: 'eventName')],
metricHeaders: [new Header(name: 'eventValue'), new Header(name: 'eventCount'), new Header(name: 'transactions'), new Header(name: 'purchaseRevenue')],
rows: [
new Row(dimensionValues: [new Value(value: '20230101')], metricValues: [new Value(value: '5.0'), new Value(value: '18'), new Value(value: '36'), new Value(value: '60.0')]),
new Row(dimensionValues: [new Value(value: '20230102')], metricValues: [new Value(value: '5.0'), new Value(value: '13'), new Value(value: '23'), new Value(value: '37.0')]),
],
totals: [new Row(metricValues: [new Value(value: '10.0'), new Value(value: '31'), new Value(value: '59'), new Value(value: '97.0')])]
)
when:
Ga4InsightsApiResponse mergedResponse = GoogleAnalyticsResponseUtils.mergeBatchResponse(visitorsResponse, eventsResponse)
then:
mergedResponse.dimensionHeaders == [new Header(name: 'date')]
mergedResponse.metricHeaders == [new Header(name: 'totalUsers'), new Header(name: 'eventValue'), new Header(name: 'eventCount'), new Header(name: 'transactions'), new Header(name: 'purchaseRevenue')]
mergedResponse.rows == [
new Row(dimensionValues: [new Value(value: '20230101')], metricValues: [new Value(value: '10'), new Value(value: '5.0'), new Value(value: '18'), new Value(value: '36'), new Value(value: '60.0')]),
new Row(dimensionValues: [new Value(value: '20230102')], metricValues: [new Value(value: '13'), new Value(value: '5.0'), new Value(value: '13'), new Value(value: '23'), new Value(value: '37.0')]),
]
mergedResponse.totals == [
new Row(metricValues: [new Value(value: '15'), new Value(value: '10.0'), new Value(value: '31'), new Value(value: '59'), new Value(value: '97.0')])
]
}</pre>
</div>
<div class="diff-panel right">
<h3>JUnit 5 (Java)</h3>
<pre>@Test
void shouldMergeBatchResponsesWithAllEvents() {
// given
Ga4InsightsApiResponse visitorsResponse = new Ga4InsightsApiResponse();
visitorsResponse.setDimensionHeaders(List.of(new Header("date")));
visitorsResponse.setMetricHeaders(List.of(new Header("totalUsers")));
visitorsResponse.setRows(List.of(
createRow(List.of("20230101"), List.of("10")),
createRow(List.of("20230102"), List.of("13"))
));
visitorsResponse.setTotals(List.of(createRowWithMetricsOnly(List.of("15"))));
Ga4InsightsApiResponse eventsResponse = new Ga4InsightsApiResponse();
eventsResponse.setDimensionHeaders(List.of(new Header("date"), new Header("eventName")));
eventsResponse.setMetricHeaders(List.of(
new Header("eventValue"),
new Header("eventCount"),
new Header("transactions"),
new Header("purchaseRevenue")
));
eventsResponse.setRows(List.of(
createRow(List.of("20230101"), List.of("5.0", "18", "36", "60.0")),
createRow(List.of("20230102"), List.of("5.0", "13", "23", "37.0"))
));
eventsResponse.setTotals(List.of(createRowWithMetricsOnly(List.of("10.0", "31", "59", "97.0"))));
// when
Ga4InsightsApiResponse mergedResponse = GoogleAnalyticsResponseUtils.mergeBatchResponse(visitorsResponse, eventsResponse);
// then
assertThat(mergedResponse.getDimensionHeaders()).containsExactly(new Header("date"));
assertThat(mergedResponse.getMetricHeaders()).containsExactly(
new Header("totalUsers"),
new Header("eventValue"),
new Header("eventCount"),
new Header("transactions"),
new Header("purchaseRevenue")
);
assertThat(mergedResponse.getRows()).containsExactly(
createRow(List.of("20230101"), List.of("10", "5.0", "18", "36", "60.0")),
createRow(List.of("20230102"), List.of("13", "5.0", "13", "23", "37.0"))
);
assertThat(mergedResponse.getTotals()).containsExactly(
createRowWithMetricsOnly(List.of("15", "10.0", "31", "59", "97.0"))
);
}</pre>
</div>
</div>
<div class="summary">
<p><strong>Changes:</strong> Test name converted to camelCase (WithAllEvents). Tests case where every visitor date has matching events. Both responses fully populated - no zero-filling needed.</p>
</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