Once you have the PRD spec for your tutorial, here are the steps you will follow to create the promo:
A TutorialIdentifier
is a unique string. Create a new ID for your tutorial and add it to tutorial_identifiers.h
and .cc
.
In the same file, you should also create your “metrics prefix”, which will be used for recording histograms. Unlike the tutorial ID, the histogram prefix should be CamelCase with no special characters or spaces.
Finally, add the metrics prefix you defined above to the “TutorialID” variants block in /tools/metrics/histograms/metadata/user_education/histograms.xml
. Be sure to use the histogram prefix and not the full tutorial name/ID.
In browser_user_education_service.cc
, in MaybeRegisterChromeTutorials()
, you should create your TutorialDescription
and register it with the provided TutorialRegistry
.
The basic pattern is as follows:
// Create the tutorial with histograms and steps: auto my_tutorial_description = TutorialDescription::Create<kMyTutorialMetricPrefix>( // Tutorial steps go here... ); // Add metadata. Note that this could be assigning an entire metadata object // or setting individual fields of the existing `metadata` member. // The minimum recommended fields are "additional_description", "milestone", // and "owners"; in the future these will become required. my_tutorial_description.metadata = ... // Actually register the tutorial: tutorial_registry.AddTutorial( kMyTutorialId, std::move(my_tutorial_description));
All of this should be fairly straightforward except the steps, and there are plenty of examples in the existing code.
There are four general kinds of steps, all defined in tutorial_descriptions.h
, and all of which target a UI element by ElementIdentifier
:
ElementTracker
on the specified element..Then(...)
are executed; else the steps in .Else(...)
(optional) are executed.Each step can be further modified by member functions on either the step class or the base Step
class. These are things like specifying what context to look for the target element in, whether the element must be present at the start or end of the step, etc.
See Help Bubbles for more information on UI elements, identifiers, contexts, etc.
If you have multiple variations on a Tutorial based on UI state or some easily- checkable condition, then using If
or IfView
is preferable to creating multiple versions of the Tutorial. This is especially true if the Tutorial is repeatable and running through it once changes the state in such a way that the other variation would need to be shown. (Example: Tab Groups tutorial created a tab group, so some of the bubbles need to change to reference the fact that there is already a tab group).
Note that the “progress bar” shown in each tutorial bubble is based on the longest possible journey through the Tutorial, so if a conditional step skips steps or shows an abridged version of the tutorial, the progress may jump from e.g. 1/6 to 3/6.
When creating Tutorials, the flow should be:
EventStep
or HiddenStep
)If (3) involves anchoring the next bubble to an element that will appear as a result of the action prompted in (1), you can omit (2). This is because there is an implied “wait for the target element to become visible” in all BubbleStep
s.
On the other hand, if (1) and (3) both reference UI elements that are already visible when the Tutorial starts, the first bubble will show, immediately be hidden, and then the second bubble will show; the user will never actually see the first bubble. In this case (2) is mandatory and should watch for either the user input or a resulting event or UI change.
The final Tutorial step must be a bubble step, and will mark the “success” state. It may be given additional buttons or icons reflecting this state. This bubble will persist until the user dismisses it, or it is forced to be hidden for other reasons (such as the UI it is anchored to disappearing).
Just generally, think about how your UI works. Think about the things the user might do and how the UI might react. For example, if there‘s a chance the user is likely to dismiss an element you want to show a bubble on in a way that won’t allow the tutorial to continue, consider anchoring the bubble elsewhere.
Similarly, are there any circumstances in which a particular step might fail to happen, even if the user performs the action you tell them to? If so, then you probably need to rethink how your steps work.
Typically this is done through a Tutorial Feature Promo (IPH) or through the “What's New” Page. For more information on these entry points, check out the Getting Started guide.
If your tutorial launches from an IPH, you can test it any of the ways you could test an IPH, suggestions are in the documentation.
You can also launch your Tutorial directly from the tester page (chrome://user-education-internals). Note that unlike IPH, you do not need to have the starting point of the tutorial present when you click the “Launch” button; you merely need to be able to bring it up in 20-30 seconds. The tutorial will start as soon as the anchor view for the first bubble of the tutorial becomes visible.
For automated testing, you can:
interactive_ui_tests
test.In the second case, press the promo's action button to start the Tutorial.
To launch a Tutorial directly in an interactive_ui_tests
test, invoke the instance of TutorialService
you get from the current profile's UserEducationService
via UserEducationServiceFactory::GetForBrowserContext()
.
We recommend using an InteractiveBrowserTest
(i.e. Kombucha) rather than a vanilla InProcessBrowserTest
because of the ability to simulate user input. As you perform the inputs that trigger the different tutorial steps, you can check for the expected help bubbles and their contents using the element identifiers defined in HelpBubbleView
(if they‘re Views) or InstrumentWebContents()
and WaitForStateChange()
to find the bubble if it’s in a WebUI in a tab.
We also recommend using PressButton()
, SelectMenuItem()
, etc. instead of MoveMouse()
and PressMouse()
wherever possible; you should have separate tests for the responsiveness of your feature's UI; for testing Tutorials the goal is merely to ensure that each bubble appears as expected.
Please reach out to Frizzle Team for more information.