├── .github └── workflows │ └── main.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── example ├── main.dart ├── pubspec.lock └── pubspec.yaml ├── lib ├── network_image_mock.dart └── src │ └── network_image_mock.dart ├── pubspec.lock ├── pubspec.yaml └── test └── network_image_mock_test.dart /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | name: Lint & Test 3 | jobs: 4 | build: 5 | name: Build and Test on ${{ matrix.os }} 6 | runs-on: ${{ matrix.os }} 7 | timeout-minutes: 10 8 | strategy: 9 | matrix: 10 | os: [ubuntu-latest] 11 | steps: 12 | - uses: actions/checkout@v1 13 | - uses: actions/setup-java@v1 14 | with: 15 | java-version: "12.x" 16 | - uses: subosito/flutter-action@v1 17 | with: 18 | channel: "stable" 19 | - uses: stelynx/dart-full-coverage@v1.0.3 20 | with: 21 | package: network_image_mock 22 | - run: flutter pub get 23 | - run: flutter analyze 24 | - run: flutter test --coverage . 25 | - uses: codecov/codecov-action@v1.0.2 26 | with: 27 | token: ${{secrets.CODECOV_TOKEN}} 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Exceptions to above rules. 37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 38 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 2.1.1 4 | 5 | Update `mockito`. 6 | 7 | ## 2.1.0 8 | 9 | Update `mockito` and provide support for mocking SVG image requests. 10 | 11 | ## 2.0.1 12 | 13 | Update `mockito` dependency and `pubspec.lock` files. 14 | 15 | ## 2.0.0 16 | 17 | Support for null safety! 18 | 19 | ## 1.1.0 20 | 21 | Change how mocking response's `listen` works. 22 | 23 | ## 1.0.2 24 | 25 | Set compression state of response of mocked client to "not compressed" 26 | to resolve issue with flutter development channel. 27 | 28 | ## 1.0.1 29 | 30 | Add example. 31 | 32 | ## 1.0.0 33 | 34 | Official release. 35 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Network Image Mock 2 | 3 | The rules are quite simple. 4 | 5 | ## Issues 6 | 7 | Whenever you open an issue, start issue title with **SLNIM-#:**, where **#** denotes 8 | the number of issue (this is not to be confused with GitHub numbering, since that numbering also includes pull requests). So, if the latest issue has a number SLNIM-13, you name the issue like _SLNIM-14: Bump mockito_. 9 | 10 | However, if you just have a question, omit the numbering! 11 | 12 | ## Pull requests 13 | 14 | Before you open a pull request, always open an issue first! After that, 15 | you open a pull request which should be named the same as issue, with 16 | **SLNIM-#:** the same as the issue of course. 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Stelynx 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Network Image Mock 2 | 3 | [![Pub Version](https://img.shields.io/pub/v/network_image_mock?color=%233dc6fd&logo=flutter&logoColor=%233dc6fd)](https://pub.dev/packages/network_image_mock) 4 | ![Lint & Test](https://github.com/stelynx/network_image_mock/workflows/Lint%20&%20Test/badge.svg) 5 | [![codecov.io](https://codecov.io/gh/stelynx/network_image_mock/branch/master/graphs/badge.svg)](https://codecov.io/gh/stelynx/network_image_mock/branch/master) 6 | ![Null safety](https://img.shields.io/badge/null%20safety-^2.0.0-brightgreen) 7 | ![No null safety](https://img.shields.io/badge/no%20null%20safety-1.1.0-orange) 8 | ![GitHub Repo stars](https://img.shields.io/github/stars/stelynx/network_image_mock?color=gold&logo=github&style=plastic) 9 | ![GitHub contributors](https://img.shields.io/github/contributors/stelynx/network_image_mock?logo=github) 10 | ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/stelynx/network_image_mock) 11 | [![GitHub](https://img.shields.io/github/license/stelynx/network_image_mock)](LICENSE) 12 | 13 | A utility for providing mocked response to `Image.network` in Flutter widget tests. 14 | 15 | ## Introduction 16 | 17 | Since you are here you probably already know that calling Image.network results in 400 18 | response in Flutter widget tests. The reason for this is that default HTTP client in tests 19 | always return a 400. 20 | 21 | So, what can we do about it? Instead of copying the whole code over and over again for mocking 22 | the HTTP client, I created this package. It is heavily inspired by [roughike/image_test_utils](https://github.com/roughike/image_test_utils), however that package is not being maintained despite multiple pull requests 23 | asking for bumping the `mockito` version and making the package usable again. 24 | 25 | ## Installing 26 | 27 | ### Null safety 28 | 29 | This package should be installed under `dev_dependencies` with 30 | 31 | ```yaml 32 | dev_dependencies: 33 | network_image_mock: ^2.0.1 34 | ``` 35 | 36 | ### Without null safety (deprecated) 37 | 38 | If you have legacy unmigrated code that does not use Null safety, install under `dev_dependencies` with 39 | 40 | ```yaml 41 | dev_dependencies: 42 | network_image_mock: 1.1.0 43 | ``` 44 | 45 | ## Example 46 | 47 | The package is quite straightforward to use. All you have to do is include it in your test 48 | file and wrap widget testing functions that require proper `Image.network` response in 49 | `mockNetworkImagesFor()` function provided by this package. A full test example could look like this. 50 | 51 | ```dart 52 | import 'package:flutter/material.dart'; 53 | import 'package:flutter_test/flutter_test.dart'; 54 | import 'package:network_image_mock/network_image_mock.dart'; 55 | 56 | Widget makeTestableWidget() => MaterialApp(home: Image.network('')); 57 | 58 | void main() { 59 | testWidgets( 60 | 'should properly mock Image.network and not crash', 61 | (WidgetTester tester) async { 62 | mockNetworkImagesFor(() => tester.pumpWidget(makeTestableWidget())); 63 | }, 64 | ); 65 | } 66 | ``` 67 | 68 | This is actually an example taken from tests for this package. 69 | 70 | ## Contributing 71 | 72 | There is not much to contribute since the package serves its purpose, however, in chance of needing to bump or adjust some version, or any other suggestion for that matter, please read [CONTRIBUTING](CONTRIBUTING.md). 73 | -------------------------------------------------------------------------------- /example/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:network_image_mock/network_image_mock.dart'; 4 | 5 | class MyApp extends StatelessWidget { 6 | // This widget is the root of your application. 7 | @override 8 | Widget build(BuildContext context) { 9 | return MaterialApp( 10 | home: Image.network('https://example.com/some_image.jpg'), 11 | ); 12 | } 13 | } 14 | 15 | void main() { 16 | testWidgets( 17 | 'should properly mock Image.network and not crash', 18 | (WidgetTester tester) async { 19 | mockNetworkImagesFor(() => tester.pumpWidget(MyApp())); 20 | }, 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "40.0.0" 11 | analyzer: 12 | dependency: transitive 13 | description: 14 | name: analyzer 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "4.1.0" 18 | args: 19 | dependency: transitive 20 | description: 21 | name: args 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.0.0" 25 | async: 26 | dependency: transitive 27 | description: 28 | name: async 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.8.2" 32 | boolean_selector: 33 | dependency: transitive 34 | description: 35 | name: boolean_selector 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "2.1.0" 39 | build: 40 | dependency: transitive 41 | description: 42 | name: build 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "2.3.0" 46 | built_collection: 47 | dependency: transitive 48 | description: 49 | name: built_collection 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "5.0.0" 53 | built_value: 54 | dependency: transitive 55 | description: 56 | name: built_value 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "8.0.6" 60 | characters: 61 | dependency: transitive 62 | description: 63 | name: characters 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.2.0" 67 | charcode: 68 | dependency: transitive 69 | description: 70 | name: charcode 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.3.1" 74 | clock: 75 | dependency: transitive 76 | description: 77 | name: clock 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "1.1.0" 81 | code_builder: 82 | dependency: transitive 83 | description: 84 | name: code_builder 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "4.0.0" 88 | collection: 89 | dependency: transitive 90 | description: 91 | name: collection 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "1.16.0" 95 | convert: 96 | dependency: transitive 97 | description: 98 | name: convert 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "3.0.0" 102 | crypto: 103 | dependency: transitive 104 | description: 105 | name: crypto 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "3.0.0" 109 | dart_style: 110 | dependency: transitive 111 | description: 112 | name: dart_style 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "2.2.3" 116 | fake_async: 117 | dependency: transitive 118 | description: 119 | name: fake_async 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "1.3.0" 123 | file: 124 | dependency: transitive 125 | description: 126 | name: file 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "6.1.0" 130 | fixnum: 131 | dependency: transitive 132 | description: 133 | name: fixnum 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "1.0.0" 137 | flutter: 138 | dependency: "direct main" 139 | description: flutter 140 | source: sdk 141 | version: "0.0.0" 142 | flutter_test: 143 | dependency: "direct dev" 144 | description: flutter 145 | source: sdk 146 | version: "0.0.0" 147 | glob: 148 | dependency: transitive 149 | description: 150 | name: glob 151 | url: "https://pub.dartlang.org" 152 | source: hosted 153 | version: "2.0.0" 154 | logging: 155 | dependency: transitive 156 | description: 157 | name: logging 158 | url: "https://pub.dartlang.org" 159 | source: hosted 160 | version: "1.0.2" 161 | matcher: 162 | dependency: transitive 163 | description: 164 | name: matcher 165 | url: "https://pub.dartlang.org" 166 | source: hosted 167 | version: "0.12.11" 168 | material_color_utilities: 169 | dependency: transitive 170 | description: 171 | name: material_color_utilities 172 | url: "https://pub.dartlang.org" 173 | source: hosted 174 | version: "0.1.4" 175 | meta: 176 | dependency: transitive 177 | description: 178 | name: meta 179 | url: "https://pub.dartlang.org" 180 | source: hosted 181 | version: "1.7.0" 182 | mockito: 183 | dependency: transitive 184 | description: 185 | name: mockito 186 | url: "https://pub.dartlang.org" 187 | source: hosted 188 | version: "5.2.0" 189 | network_image_mock: 190 | dependency: "direct dev" 191 | description: 192 | path: ".." 193 | relative: true 194 | source: path 195 | version: "2.1.0" 196 | package_config: 197 | dependency: transitive 198 | description: 199 | name: package_config 200 | url: "https://pub.dartlang.org" 201 | source: hosted 202 | version: "2.0.0" 203 | path: 204 | dependency: transitive 205 | description: 206 | name: path 207 | url: "https://pub.dartlang.org" 208 | source: hosted 209 | version: "1.8.1" 210 | pedantic: 211 | dependency: transitive 212 | description: 213 | name: pedantic 214 | url: "https://pub.dartlang.org" 215 | source: hosted 216 | version: "1.11.0" 217 | pub_semver: 218 | dependency: transitive 219 | description: 220 | name: pub_semver 221 | url: "https://pub.dartlang.org" 222 | source: hosted 223 | version: "2.0.0" 224 | sky_engine: 225 | dependency: transitive 226 | description: flutter 227 | source: sdk 228 | version: "0.0.99" 229 | source_gen: 230 | dependency: transitive 231 | description: 232 | name: source_gen 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "1.2.2" 236 | source_span: 237 | dependency: transitive 238 | description: 239 | name: source_span 240 | url: "https://pub.dartlang.org" 241 | source: hosted 242 | version: "1.8.2" 243 | stack_trace: 244 | dependency: transitive 245 | description: 246 | name: stack_trace 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "1.10.0" 250 | stream_channel: 251 | dependency: transitive 252 | description: 253 | name: stream_channel 254 | url: "https://pub.dartlang.org" 255 | source: hosted 256 | version: "2.1.0" 257 | string_scanner: 258 | dependency: transitive 259 | description: 260 | name: string_scanner 261 | url: "https://pub.dartlang.org" 262 | source: hosted 263 | version: "1.1.0" 264 | term_glyph: 265 | dependency: transitive 266 | description: 267 | name: term_glyph 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "1.2.0" 271 | test_api: 272 | dependency: transitive 273 | description: 274 | name: test_api 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "0.4.9" 278 | typed_data: 279 | dependency: transitive 280 | description: 281 | name: typed_data 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "1.3.0" 285 | vector_math: 286 | dependency: transitive 287 | description: 288 | name: vector_math 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "2.1.2" 292 | watcher: 293 | dependency: transitive 294 | description: 295 | name: watcher 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "1.0.0" 299 | yaml: 300 | dependency: transitive 301 | description: 302 | name: yaml 303 | url: "https://pub.dartlang.org" 304 | source: hosted 305 | version: "3.1.0" 306 | sdks: 307 | dart: ">=2.17.0-0 <3.0.0" 308 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: An example for network_image_mock package. 3 | version: 1.0.0 4 | 5 | environment: 6 | sdk: ">=2.12.0 <3.0.0" 7 | 8 | dependencies: 9 | flutter: 10 | sdk: flutter 11 | 12 | dev_dependencies: 13 | flutter_test: 14 | sdk: flutter 15 | network_image_mock: 16 | path: ../ 17 | 18 | flutter: 19 | uses-material-design: true 20 | -------------------------------------------------------------------------------- /lib/network_image_mock.dart: -------------------------------------------------------------------------------- 1 | library network_image_mock; 2 | 3 | export './src/network_image_mock.dart' show mockNetworkImagesFor; 4 | -------------------------------------------------------------------------------- /lib/src/network_image_mock.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | import 'dart:io'; 4 | 5 | import 'package:mockito/mockito.dart'; 6 | 7 | /// Runs [body] in separate [Zone] with [MockHttpClient]. 8 | R mockNetworkImagesFor(R body()) { 9 | return HttpOverrides.runZoned( 10 | body, 11 | createHttpClient: (_) => createMockImageHttpClient(), 12 | ); 13 | } 14 | 15 | class MockHttpClient extends Mock implements HttpClient { 16 | @override 17 | Future getUrl(Uri? url) { 18 | // ignore: invalid_use_of_visible_for_testing_member 19 | return super.noSuchMethod(Invocation.method(#getUrl, [url]), 20 | returnValue: Future.value(MockHttpClientRequest())); 21 | } 22 | } 23 | 24 | class MockHttpClientRequest extends Mock implements HttpClientRequest { 25 | @override 26 | // ignore: invalid_use_of_visible_for_testing_member 27 | HttpHeaders get headers => super.noSuchMethod(Invocation.getter(#headers), 28 | returnValue: MockHttpHeaders()); 29 | 30 | @override 31 | Future close() => 32 | // ignore: invalid_use_of_visible_for_testing_member 33 | super.noSuchMethod(Invocation.method(#close, []), 34 | returnValue: Future.value(MockHttpClientResponse())); 35 | } 36 | 37 | class MockHttpClientResponse extends Mock implements HttpClientResponse { 38 | @override 39 | HttpClientResponseCompressionState get compressionState => 40 | // ignore: invalid_use_of_visible_for_testing_member 41 | super.noSuchMethod(Invocation.getter(#compressionState), 42 | returnValue: HttpClientResponseCompressionState.notCompressed); 43 | 44 | @override 45 | int get contentLength => 46 | // ignore: invalid_use_of_visible_for_testing_member 47 | super.noSuchMethod(Invocation.getter(#contentLength), returnValue: 0); 48 | 49 | @override 50 | int get statusCode => 51 | // ignore: invalid_use_of_visible_for_testing_member 52 | super.noSuchMethod(Invocation.getter(#statusCode), returnValue: 0); 53 | 54 | @override 55 | StreamSubscription> listen(void Function(List)? onData, 56 | {Function? onError, void Function()? onDone, bool? cancelOnError}) => 57 | // ignore: invalid_use_of_visible_for_testing_member 58 | super.noSuchMethod( 59 | Invocation.method(#listen, [ 60 | onData, 61 | ], { 62 | Symbol("onError"): onError, 63 | Symbol("onDone"): onDone, 64 | Symbol("cancelOnError"): cancelOnError, 65 | }), 66 | returnValue: MockStreamSubscription>()); 67 | } 68 | 69 | class MockHttpHeaders extends Mock implements HttpHeaders {} 70 | 71 | class MockStreamSubscription extends Mock implements StreamSubscription {} 72 | 73 | /// Returns a [MockHttpClient] that responds with demo image to all requests. 74 | MockHttpClient createMockImageHttpClient() { 75 | final MockHttpClient client = MockHttpClient(); 76 | final MockHttpClientRequest request = MockHttpClientRequest(); 77 | final MockHttpClientRequest svgRequest = MockHttpClientRequest(); 78 | 79 | when(client.getUrl(any)).thenAnswer((Invocation invocation) { 80 | return Future.value( 81 | invocation.positionalArguments[0].path.endsWith(".svg") 82 | ? svgRequest 83 | : request, 84 | ); 85 | }); 86 | 87 | mockRequestResponse(request: request, image: image); 88 | mockRequestResponse(request: svgRequest, image: svgImage); 89 | 90 | request.close(); 91 | svgRequest.close(); 92 | 93 | return client; 94 | } 95 | 96 | void mockRequestResponse({ 97 | required MockHttpClientRequest request, 98 | required List image, 99 | }) { 100 | final MockHttpClientResponse response = MockHttpClientResponse(); 101 | final MockHttpHeaders headers = MockHttpHeaders(); 102 | when(request.headers).thenReturn(headers); 103 | when(request.close()) 104 | .thenAnswer((_) => Future.value(response)); 105 | when(response.compressionState) 106 | .thenReturn(HttpClientResponseCompressionState.notCompressed); 107 | when(response.contentLength).thenReturn(image.length); 108 | when(response.statusCode).thenReturn(HttpStatus.ok); 109 | when(response.listen( 110 | any, 111 | onError: anyNamed("onError"), 112 | onDone: anyNamed("onDone"), 113 | cancelOnError: anyNamed("cancelOnError"), 114 | )).thenAnswer((Invocation invocation) { 115 | final void Function(List) onData = invocation.positionalArguments[0]; 116 | final onDone = invocation.namedArguments[#onDone]; 117 | final onError = invocation.namedArguments[#onError]; 118 | final bool? cancelOnError = invocation.namedArguments[#cancelOnError]; 119 | 120 | return Stream>.fromIterable(>[image]).listen(onData, 121 | onDone: onDone, onError: onError, cancelOnError: cancelOnError); 122 | }); 123 | } 124 | 125 | //transparent pixel in png format 126 | final image = base64Decode( 127 | "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==", 128 | ); 129 | 130 | //one pixel in svg format 131 | final svgImage = base64Decode( 132 | "PHN2ZyBoZWlnaHQ9IjEiIHdpZHRoPSIxIj48L3N2Zz4=", 133 | ); 134 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "40.0.0" 11 | analyzer: 12 | dependency: transitive 13 | description: 14 | name: analyzer 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "4.1.0" 18 | args: 19 | dependency: transitive 20 | description: 21 | name: args 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.0.0" 25 | async: 26 | dependency: transitive 27 | description: 28 | name: async 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.8.2" 32 | boolean_selector: 33 | dependency: transitive 34 | description: 35 | name: boolean_selector 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "2.1.0" 39 | build: 40 | dependency: transitive 41 | description: 42 | name: build 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "2.3.0" 46 | built_collection: 47 | dependency: transitive 48 | description: 49 | name: built_collection 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "5.0.0" 53 | built_value: 54 | dependency: transitive 55 | description: 56 | name: built_value 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "8.0.6" 60 | characters: 61 | dependency: transitive 62 | description: 63 | name: characters 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.2.0" 67 | charcode: 68 | dependency: transitive 69 | description: 70 | name: charcode 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.3.1" 74 | clock: 75 | dependency: transitive 76 | description: 77 | name: clock 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "1.1.0" 81 | code_builder: 82 | dependency: transitive 83 | description: 84 | name: code_builder 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "4.0.0" 88 | collection: 89 | dependency: transitive 90 | description: 91 | name: collection 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "1.16.0" 95 | convert: 96 | dependency: transitive 97 | description: 98 | name: convert 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "3.0.0" 102 | crypto: 103 | dependency: transitive 104 | description: 105 | name: crypto 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "3.0.0" 109 | dart_style: 110 | dependency: transitive 111 | description: 112 | name: dart_style 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "2.2.3" 116 | fake_async: 117 | dependency: transitive 118 | description: 119 | name: fake_async 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "1.3.0" 123 | file: 124 | dependency: transitive 125 | description: 126 | name: file 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "6.1.0" 130 | fixnum: 131 | dependency: transitive 132 | description: 133 | name: fixnum 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "1.0.0" 137 | flutter: 138 | dependency: "direct main" 139 | description: flutter 140 | source: sdk 141 | version: "0.0.0" 142 | flutter_test: 143 | dependency: "direct dev" 144 | description: flutter 145 | source: sdk 146 | version: "0.0.0" 147 | glob: 148 | dependency: transitive 149 | description: 150 | name: glob 151 | url: "https://pub.dartlang.org" 152 | source: hosted 153 | version: "2.0.0" 154 | logging: 155 | dependency: transitive 156 | description: 157 | name: logging 158 | url: "https://pub.dartlang.org" 159 | source: hosted 160 | version: "1.0.2" 161 | matcher: 162 | dependency: transitive 163 | description: 164 | name: matcher 165 | url: "https://pub.dartlang.org" 166 | source: hosted 167 | version: "0.12.11" 168 | material_color_utilities: 169 | dependency: transitive 170 | description: 171 | name: material_color_utilities 172 | url: "https://pub.dartlang.org" 173 | source: hosted 174 | version: "0.1.4" 175 | meta: 176 | dependency: transitive 177 | description: 178 | name: meta 179 | url: "https://pub.dartlang.org" 180 | source: hosted 181 | version: "1.7.0" 182 | mockito: 183 | dependency: "direct main" 184 | description: 185 | name: mockito 186 | url: "https://pub.dartlang.org" 187 | source: hosted 188 | version: "5.2.0" 189 | package_config: 190 | dependency: transitive 191 | description: 192 | name: package_config 193 | url: "https://pub.dartlang.org" 194 | source: hosted 195 | version: "2.0.0" 196 | path: 197 | dependency: transitive 198 | description: 199 | name: path 200 | url: "https://pub.dartlang.org" 201 | source: hosted 202 | version: "1.8.1" 203 | pedantic: 204 | dependency: transitive 205 | description: 206 | name: pedantic 207 | url: "https://pub.dartlang.org" 208 | source: hosted 209 | version: "1.11.0" 210 | pub_semver: 211 | dependency: transitive 212 | description: 213 | name: pub_semver 214 | url: "https://pub.dartlang.org" 215 | source: hosted 216 | version: "2.0.0" 217 | sky_engine: 218 | dependency: transitive 219 | description: flutter 220 | source: sdk 221 | version: "0.0.99" 222 | source_gen: 223 | dependency: transitive 224 | description: 225 | name: source_gen 226 | url: "https://pub.dartlang.org" 227 | source: hosted 228 | version: "1.2.2" 229 | source_span: 230 | dependency: transitive 231 | description: 232 | name: source_span 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "1.8.2" 236 | stack_trace: 237 | dependency: transitive 238 | description: 239 | name: stack_trace 240 | url: "https://pub.dartlang.org" 241 | source: hosted 242 | version: "1.10.0" 243 | stream_channel: 244 | dependency: transitive 245 | description: 246 | name: stream_channel 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "2.1.0" 250 | string_scanner: 251 | dependency: transitive 252 | description: 253 | name: string_scanner 254 | url: "https://pub.dartlang.org" 255 | source: hosted 256 | version: "1.1.0" 257 | term_glyph: 258 | dependency: transitive 259 | description: 260 | name: term_glyph 261 | url: "https://pub.dartlang.org" 262 | source: hosted 263 | version: "1.2.0" 264 | test_api: 265 | dependency: transitive 266 | description: 267 | name: test_api 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "0.4.9" 271 | typed_data: 272 | dependency: transitive 273 | description: 274 | name: typed_data 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "1.3.0" 278 | vector_math: 279 | dependency: transitive 280 | description: 281 | name: vector_math 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "2.1.2" 285 | watcher: 286 | dependency: transitive 287 | description: 288 | name: watcher 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "1.0.0" 292 | yaml: 293 | dependency: transitive 294 | description: 295 | name: yaml 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "3.1.0" 299 | sdks: 300 | dart: ">=2.17.0-0 <3.0.0" 301 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: network_image_mock 2 | description: Utility for providing mocked Image.network response in Flutter widget tests. 3 | version: 2.1.1 4 | homepage: https://github.com/stelynx/network_image_mock 5 | repository: https://github.com/stelynx/network_image_mock 6 | 7 | environment: 8 | sdk: ">=2.12.0 <3.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | mockito: ^5.2.0 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | -------------------------------------------------------------------------------- /test/network_image_mock_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | import 'package:network_image_mock/src/network_image_mock.dart'; 6 | 7 | Widget makeTestableWidget() => MaterialApp(home: Image.network('')); 8 | 9 | void main() { 10 | group('createMockImageHttpClient', () { 11 | test('should return an image', () async { 12 | final MockHttpClient client = createMockImageHttpClient(); 13 | 14 | final HttpClientRequest request = await client.getUrl(Uri()); 15 | final HttpClientResponse response = await request.close(); 16 | 17 | await response 18 | .listen((List img) => expect(img, equals(image))) 19 | .asFuture(); 20 | }); 21 | 22 | test('should return image when listening with all callbacks', () async { 23 | final MockHttpClient client = createMockImageHttpClient(); 24 | 25 | final HttpClientRequest request = await client.getUrl(Uri()); 26 | final HttpClientResponse response = await request.close(); 27 | 28 | await response 29 | .listen((List img) => expect(img, equals(image)), 30 | onError: (err, stack) {}, onDone: () {}, cancelOnError: true) 31 | .asFuture(); 32 | }); 33 | }); 34 | 35 | group('mockNetworkImageFor', () { 36 | testWidgets( 37 | 'should properly mock Image.network and not crash', 38 | (WidgetTester tester) async { 39 | await mockNetworkImagesFor( 40 | () => tester.pumpWidget(makeTestableWidget())); 41 | }, 42 | ); 43 | }); 44 | } 45 | --------------------------------------------------------------------------------