Add example test, update example READMEs (#91130)
diff --git a/examples/api/README.md b/examples/api/README.md index b0e6ca1..2c1a878 100644 --- a/examples/api/README.md +++ b/examples/api/README.md
@@ -1,67 +1,135 @@ # API Example Code -This directory contains the API sample code that is referenced from the -API documentation in each class. +This directory contains the API sample code that is referenced from the API +documentation in the framework. -They can be run individually by just specifying the path to the example on the -command line (or in the run configuration of an IDE). +The examples can be run individually by just specifying the path to the example +on the command line (or in the run configuration of an IDE). -For example, to run, in Chrome, the first example from the `Curve2D` class, you -would run it like so, from this [api](.) directory: +For example (no pun intended!), to run, the first example from the `Curve2D` +class in Chrome, you would run it like so from the [api](.) directory: ``` % flutter run -d chrome lib/animation/curves/curve2_d.0.dart ``` -These same examples are available on the API docs site. For instance, the -example above is available on [this -page](https://api.flutter.dev/flutter/animation/Curve2D-class.html#animation.Curve2D.1). -Most of them are available as interactive examples in Dartpad, but some just -don't make sense on the web, and so are available as standalone examples that -can be run here. +All of these same examples are available on the API docs site. For instance, the +example above is available on [this page]( +https://api.flutter.dev/flutter/animation/Curve2D-class.html#animation.Curve2D.1). +Most of the samples are available as interactive examples in +[Dartpad](https://dartpad.dev), but some (the ones marked with `{@tool sample}` +in the framework source code), just don't make sense on the web, and so are +available as standalone examples that can be run here. For instance, setting the +system overlay style doesn't make sense on the web (it only changes the +notification area background color on Android), so you can run the example for +that on an Android device like so: + +``` +% flutter run -d MyAndroidDevice lib/services/system_chrome/system_chrome.set_system_u_i_overlay_style.1.dart +``` ## Naming The naming scheme for the files is similar to the hierarchy under [packages/flutter/lib/src](../../packages/flutter/lib/src), except that the -files are represented as directories, and each sample in each file as a separate -file in that directory. So, for the example above, the examples are from the +files are represented as directories (without the `.dart` suffix), and each +sample in the file is a separate file in that directory. So, for the example +above, where the examples are from the [packages/flutter/lib/src/animation/curves.dart](../../packages/flutter/lib/src/animation/curves.dart) -file, the `Curve2D` class, and the first sample (hence the index "0") for that -symbol resides in the -[lib/animation/curves/curve2_d.0.dart](lib/animation/curves/curve2_d.0.dart) -file. +file, the `Curve2D` class, the first sample (hence the index "0") for that +symbol resides in the file named +[lib/animation/curves/curve2_d.0.dart](lib/animation/curves/curve2_d.0.dart). + +Symbol names are converted from "CamelCase" to "snake_case". Dots are left +between symbol names, so the first example for symbol +`InputDecoration.prefixIconConstraints` would be converted to +`input_decoration.prefix_icon_constraints.0.dart`. + +If the same example is linked to from multiple symbols, the source will be in +the canonical location for one of the symbols, and the link in the API docs +block for the other symbols will point to the first symbol's example location. ## Authoring -When authoring these examples, place a block like so in the Dartdoc -documentation for the symbol you would like to attach it to. Here's what it -might look like if you wanted to add a new example to the `Curve2D` class. First -add the stub to the symbol documentation: +> For more detailed information about authoring examples, see +> [the snippets package](https://pub.dev/packages/snippets). + +When authoring examples, first place a block in the Dartdoc documentation for +the symbol you would like to attach it to. Here's what it might look like if you +wanted to add a new example to the `Curve2D` class: ```dart -/// {@tool dartpad --template=material_scaffold} +/// {@tool dartpad} +/// Write a description of the example here. This description will appear in the +/// API web documentation to introduce the example. +/// +/// ** See code in examples/api/lib/animation/curves/curve2_d.0.dart ** +/// {@end-tool} +``` + +The "See code in" line needs to be formatted exactly as above, with no wrapping +or newlines, one space after the "`**`" at the beginning, and one space before +the "`**`" at the end, and the words "See code in" at the beginning of the line. +This is what the snippets tool and the IDE use when finding the example source +code that you are creating. + +Use `{@tool dartpad}` for Dartpad examples, and use `{@tool sample}` for +examples that shouldn't be run/shown in Dartpad. + +Once that comment block is inserted in the source code, create a new file at the +appropriate path under [`examples/api`](.). You should also add tests for your +sample code under [`examples/api/test`](./test). + +The entire example should be in a single file, so that Dartpad can load it. + +Only packages that can be loaded by Dartpad may be imported. If you use one that +hasn't been used in an example before, you may have to add it to the +[pubspec.yaml](pubspec.yaml) in the api directory. + +## Snippets + +There is another type of example that can also be authored, using `{@tool +snippet}`. Snippet examples are just written inline in the source, like so: + +```dart +/// {@tool dartpad} /// Write a description of the example here. This description will appear in the /// API web documentation to introduce the example. /// /// ```dart -/// // These are the sections you want to fill out in the template. -/// // They will be transferred to the example file when you extract it. +/// // Sample code goes here, e.g.: +/// const Widget emptyBox = SizedBox(); /// ``` /// {@end-tool} ``` -Then install the `extract_sample` command with: +The source for these snippets isn't stored under the [`examples/api`](.) +directory, or available in Dartpad in the API docs, since they're not intended +to be runnable, they just show some incomplete snippet of example code. It must +compile (in the context of the sample analyzer), but doesn't need to do +anything. See [the snippets documentation]( +https://pub.dev/packages/snippets#snippet-tool) for more information about the +context that the analyzer uses. -``` -% pub global activate snippets -``` +## Writing Tests -And run the `extract_sample` command from the Flutter repo dir: +Examples are required to have tests. There is already a "smoke test" that runs +all the API examples, just to make sure that they start up without crashing. In +addition, we also require writing tests of functionality in the examples, and +generally just do what we normally do for writing tests. The one thing that +makes it more challenging for the examples is that they can't really be written +for testability in any obvious way, since that would probably complicate the +example and make it harder to explain. -``` -$ pub global run extract_sample packages/flutter/lib/src/animation/curves.dart -``` +As an example, in regular framework code, you might include a parameter for a +`Platform` object that can be overridden by a test to supply a dummy platform, +but in the example, this would be unnecessary complexity for the example. In all +other ways, these are just normal tests. -This will create a new file in the `examples/api` directory, in this case it -would create `examples/api/lib/animation/curves/curve2_d.1.dart` +Tests go into a directory under [test](./test) that matches their location under +[lib](./lib). They are named the same as the example they are testing, with +`_test.dart` at the end, like other tests. For instance, a `LayoutBuilder` +example that resides in [`lib/widgets/layout_builder/layout_builder.0.dart`]( +./lib/widgets/layout_builder/layout_builder.0.dart) would have its tests in a +file named [`test/animation/curves/curve2_d.0_test.dart`]( +./test/widgets/layout_builder/layout_builder.0_test.dart)