|
6 | 6 | // 1. Run chrome driver with --port=4444
|
7 | 7 | // 2. Run the test from example folder with: flutter drive -d web-server --web-port 7357 --browser-name chrome --driver test_driver/integration_test.dart --target integration_test/ad_widget_test.dart
|
8 | 8 |
|
9 |
| -import 'package:flutter/widgets.dart'; |
| 9 | +import 'package:flutter/material.dart'; |
10 | 10 | import 'package:flutter_test/flutter_test.dart';
|
11 |
| -import 'package:google_adsense/google_adsense.dart'; |
| 11 | +// Ensure we don't use the singleton `adSense`, but the local copies to this plugin. |
| 12 | +import 'package:google_adsense/google_adsense.dart' hide adSense; |
12 | 13 | import 'package:integration_test/integration_test.dart';
|
13 | 14 | import 'package:web/web.dart' as web;
|
14 | 15 |
|
| 16 | +import 'test_js_interop.dart'; |
| 17 | + |
15 | 18 | const String testClient = 'test_client';
|
16 | 19 | const String testSlot = 'test_slot';
|
17 |
| -late AdSense adsense; |
| 20 | +const String testScriptUrl = |
| 21 | + 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-$testClient'; |
18 | 22 |
|
19 | 23 | void main() async {
|
20 | 24 | IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
21 | 25 |
|
| 26 | + late AdSense adsense; |
| 27 | + |
22 | 28 | setUp(() async {
|
23 | 29 | adsense = AdSense();
|
24 | 30 | });
|
25 | 31 |
|
| 32 | + tearDown(() { |
| 33 | + clearAdsByGoogleMock(); |
| 34 | + }); |
| 35 | + |
26 | 36 | group('initialization', () {
|
27 |
| - testWidgets('Initialization adds AdSense snippet to index.html', |
28 |
| - (WidgetTester _) async { |
| 37 | + testWidgets('Initialization adds AdSense snippet.', (WidgetTester _) async { |
| 38 | + final web.HTMLElement target = web.HTMLDivElement(); |
29 | 39 | // Given
|
30 |
| - const String expectedScriptUrl = |
31 |
| - 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-$testClient'; |
32 | 40 |
|
33 |
| - // When |
34 |
| - adsense.initialize(testClient); |
| 41 | + adsense.initialize(testClient, jsLoaderTarget: target); |
35 | 42 |
|
36 |
| - // Then |
37 |
| - final web.HTMLScriptElement injected = |
38 |
| - web.document.head!.lastChild! as web.HTMLScriptElement; |
39 |
| - expect(injected.src, expectedScriptUrl); |
| 43 | + final web.HTMLScriptElement? injected = |
| 44 | + target.lastElementChild as web.HTMLScriptElement?; |
| 45 | + |
| 46 | + expect(injected, isNotNull); |
| 47 | + expect(injected!.src, testScriptUrl); |
40 | 48 | expect(injected.crossOrigin, 'anonymous');
|
41 | 49 | expect(injected.async, true);
|
42 | 50 | });
|
| 51 | + |
| 52 | + testWidgets('Skips initialization if script already present.', |
| 53 | + (WidgetTester _) async { |
| 54 | + final web.HTMLScriptElement script = web.HTMLScriptElement() |
| 55 | + ..id = 'previously-injected' |
| 56 | + ..src = testScriptUrl; |
| 57 | + final web.HTMLElement target = web.HTMLDivElement()..appendChild(script); |
| 58 | + |
| 59 | + adsense.initialize(testClient, jsLoaderTarget: target); |
| 60 | + |
| 61 | + expect(target.childElementCount, 1); |
| 62 | + expect(target.firstElementChild?.id, 'previously-injected'); |
| 63 | + }); |
| 64 | + |
| 65 | + testWidgets('Skips initialization if adsense object already present.', |
| 66 | + (WidgetTester _) async { |
| 67 | + final web.HTMLElement target = web.HTMLDivElement(); |
| 68 | + |
| 69 | + // Write an empty noop object |
| 70 | + mockAdsByGoogle(() {}); |
| 71 | + |
| 72 | + adsense.initialize(testClient, jsLoaderTarget: target); |
| 73 | + |
| 74 | + expect(target.firstElementChild, isNull); |
| 75 | + }); |
43 | 76 | });
|
44 | 77 |
|
45 | 78 | group('adWidget', () {
|
46 |
| - testWidgets('AdUnitWidget is created and rendered', |
| 79 | + testWidgets('Filled ad units resize widget height', |
47 | 80 | (WidgetTester tester) async {
|
48 | 81 | // When
|
49 |
| - // TODO(sokoloff06): Mock server response |
| 82 | + mockAdsByGoogle(() { |
| 83 | + // Locate the target element, and push a red div to it... |
| 84 | + final web.Element? adTarget = |
| 85 | + web.document.querySelector('div[id^=adUnit] ins'); |
| 86 | + |
| 87 | + final web.HTMLElement fakeAd = web.HTMLDivElement() |
| 88 | + ..style.width = '320px' |
| 89 | + ..style.height = '137px' |
| 90 | + ..style.background = 'red'; |
| 91 | + |
| 92 | + adTarget! |
| 93 | + ..appendChild(fakeAd) |
| 94 | + ..setAttribute('data-ad-status', AdStatus.FILLED); |
| 95 | + }); |
50 | 96 |
|
51 | 97 | adsense.initialize(testClient);
|
| 98 | + |
52 | 99 | final Widget adUnitWidget =
|
53 |
| - adSense.adUnit(AdUnitConfiguration.displayAdUnit(adSlot: testSlot)); |
54 |
| - await tester.pumpWidget(adUnitWidget); |
55 |
| - await tester.pumpWidget( |
56 |
| - adUnitWidget); // TODO(sokoloff06): Why only works when pumping twice? |
| 100 | + adsense.adUnit(AdUnitConfiguration.displayAdUnit(adSlot: testSlot)); |
| 101 | + |
| 102 | + await pumpAdWidget(adUnitWidget, tester); |
| 103 | + |
| 104 | + // Then |
| 105 | + // Widget level |
| 106 | + expect(find.byWidget(adUnitWidget), findsOneWidget); |
| 107 | + |
| 108 | + final Size size = tester.getSize(find.byWidget(adUnitWidget)); |
| 109 | + |
| 110 | + expect(size.height, 137); |
| 111 | + }); |
| 112 | + |
| 113 | + testWidgets('Unfilled ad units collapse widget height', |
| 114 | + (WidgetTester tester) async { |
| 115 | + // When |
| 116 | + mockAdsByGoogle(() { |
| 117 | + // Locate the target element, and push a red div to it... |
| 118 | + final web.Element? adTarget = |
| 119 | + web.document.querySelector('div[id^=adUnit] ins'); |
| 120 | + |
| 121 | + // The internal styling of the Ad doesn't matter, if AdSense tells us it is UNFILLED. |
| 122 | + final web.HTMLElement fakeAd = web.HTMLDivElement() |
| 123 | + ..style.width = '320px' |
| 124 | + ..style.height = '137px' |
| 125 | + ..style.background = 'red'; |
| 126 | + |
| 127 | + adTarget! |
| 128 | + ..appendChild(fakeAd) |
| 129 | + ..setAttribute('data-ad-status', AdStatus.UNFILLED); |
| 130 | + }); |
| 131 | + |
| 132 | + adsense.initialize(testClient); |
| 133 | + final Widget adUnitWidget = |
| 134 | + adsense.adUnit(AdUnitConfiguration.displayAdUnit(adSlot: testSlot)); |
| 135 | + |
| 136 | + await pumpAdWidget(adUnitWidget, tester); |
| 137 | + |
57 | 138 | // Then
|
58 | 139 | // Widget level
|
59 | 140 | expect(find.byWidget(adUnitWidget), findsOneWidget);
|
60 |
| - expect(adUnitWidget, isA<Widget>()); |
61 | 141 |
|
62 |
| - // DOM level |
63 |
| - final web.HTMLElement? platformView = |
64 |
| - web.document.querySelector('flt-platform-view') as web.HTMLElement?; |
65 |
| - expect(platformView, isNotNull); |
66 |
| - final web.HTMLElement ins = |
67 |
| - platformView!.querySelector('ins')! as web.HTMLElement; |
68 |
| - expect(ins.style.display, 'block'); |
| 142 | + final Size size = tester.getSize(find.byWidget(adUnitWidget)); |
69 | 143 |
|
70 |
| - // TODO(sokoloff06): Validate response is rendered |
| 144 | + expect(size.height, 0); |
71 | 145 | });
|
72 | 146 | });
|
73 | 147 | }
|
| 148 | + |
| 149 | +// Pumps an AdUnit Widget into a given tester, with some parameters |
| 150 | +Future<void> pumpAdWidget(Widget adUnit, WidgetTester tester) async { |
| 151 | + await tester.pumpWidget( |
| 152 | + MaterialApp( |
| 153 | + home: Scaffold( |
| 154 | + body: Center( |
| 155 | + child: adUnit, |
| 156 | + ), |
| 157 | + ), |
| 158 | + ), |
| 159 | + ); |
| 160 | + |
| 161 | + // This extra pump is needed for the platform view to actually render in the DOM. |
| 162 | + await tester.pump(); |
| 163 | + |
| 164 | + // This extra pump is needed to simulate the async behavior of the adsense JS mock. |
| 165 | + await tester.pumpAndSettle(); |
| 166 | +} |
0 commit comments