Commit c76579ea authored by Akihiro Ota's avatar Akihiro Ota Committed by Commit Bot

ChromeVox Tutorial: Finalize UI.

This change makes the final polishes to the tutorial UI.
Please see the crbug, which includes a link to screenshots.

In addition, this change finalizes the practice areas for M88
launch. The basic navigation practice area was removed because it
doesn't offer any new information (basic navigation is already
needed to reach that lesson in the first place). The jump commands
practice area was changed to only include jumping by heading, using
some of the strings from the old tutorial (to be localized in follow-
up).

Lastly, this change fixes a few tests that were breaking due to UI
changes. We also disable one test for practice area nudges, since the
practice area for basic navigation was removed.

Fixed: 1139457
Change-Id: I925711cb48ec4b926558f67ad3a030063e4785d9
AX-Relnotes: N/A
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2504569
Commit-Queue: Akihiro Ota <akihiroota@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#825148}
parent 6e5b701a
<!-- Copyright 2020 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<style>
<style include="cr-shared-style">
#tutorial {
background: #FFF;
bottom: 0;
left: 0;
margin-bottom: 30px;
margin-top: 30px;
margin-bottom: 80px;
margin-top: 80px;
position: fixed;
right: 0;
top: 0;
......@@ -17,71 +17,81 @@
#mainMenu,
#lessonMenu,
#lessonContainer,
#mainMenuButtons,
#nav {
margin: auto;
text-align: center;
width: 50%;
text-align: start;
width: 800px;
}
#mainMenuButtons,
#lessonShortcuts {
background: #FFF;
border-radius: 4px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
margin: auto;
max-height: 500px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 2px 6px rgba(0, 0, 0, 0.15);
font-size: 22px;
}
#lessonShortcuts {
max-height: 400px;
overflow: scroll;
}
#mainMenuButtons {
background: #FFF;
border-radius: 4px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
cr-button,
cr-link-row {
font-family: 'Roboto';
font-weight: medium;
}
h1 {
font-family: 'Google Sans', 'Roboto';
font-size: 32px;
font-weight: medium;
line-height: 40px;
margin-bottom: 32px;
}
cr-button {
font-size: 16px;
font-style: normal;
line-height: 24px;
margin-bottom: 40px;
margin-inline-end: 8px;
margin-inline-start: 8px;
margin-top: 40px;
}
#navSeparator {
background: rgb(232, 234, 237);
height: 1px;
margin: 30px;
width: 800px;
}
h1,
cr-button {
font-family: Google Sans;
/* Styling for bottom navigation buttons */
#lessonNav {
display: inline-block;
float: right;
}
h1 {
display: flex;
flex-direction: column;
font-size: 32px;
line-height: 32px;
margin: 20px;
padding: 8px;
#lessonNav cr-button {
float: right;
}
#mainMenu cr-button,
#lessonMenu cr-button {
color: rgb(32, 33, 36);
font-size: 22px;
font-style: normal;
font-weight: normal;
line-height: 20px;
padding: 30px;
#menuNav {
display: inline-block;
float: left;
}
#navButtons cr-button {
color: rgb(26, 115, 232);
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 20px;
margin-bottom: 10px;
margin-inline-end: 10px;
margin-inline-start: 10px;
margin-top: 10px;
#menuNav cr-button {
float: right;
}
#exitTutorial {
margin-inline-start: 0;
}
#nextLesson {
margin-inline-end: 0;
}
</style>
......@@ -95,24 +105,24 @@ h1 {
</h1>
<div id="mainMenuHeaderHint" hidden>[[ mainMenuHeaderHint ]]</div>
<div id="mainMenuButtons">
<cr-button id="quickOrientationButton" on-click="chooseCurriculum">
[[ quickOrientation ]]
</cr-button>
<cr-button id="essentialKeysButton" on-click="chooseCurriculum">
[[ essentialKeys ]]
</cr-button>
<cr-button id="navigationButton" on-click="chooseCurriculum">
[[ navigation ]]
</cr-button>
<cr-button id="commandReferencesButton" on-click="chooseCurriculum">
[[ commandReferences ]]
</cr-button>
<cr-button id="soundsAndSettingsButton" on-click="chooseCurriculum">
[[ soundsAndSettings ]]
</cr-button>
<cr-button id="resourcesButton" on-click="chooseCurriculum">
[[ resources ]]
</cr-button>
<cr-link-row id="quickOrientationButton" class="hr"
on-click="chooseCurriculum" label="[[ quickOrientation ]]">
</cr-link-row>
<cr-link-row id="essentialKeysButton" class="hr" on-click="chooseCurriculum"
label="[[ essentialKeys ]]">
</cr-link-row>
<cr-link-row id="navigationButton" class="hr" on-click="chooseCurriculum"
label="[[ navigation ]]">
</cr-link-row>
<cr-link-row id="commandReferencesButton" class="hr"
on-click="chooseCurriculum" label="[[ commandReferences ]]">
</cr-link-row>
<cr-link-row id="soundsAndSettingsButton" class="hr"
on-click="chooseCurriculum" label="[[ soundsAndSettings ]]">
</cr-link-row>
<cr-link-row id="resourcesButton" class="hr" on-click="chooseCurriculum"
label="[[ resources ]]">
</cr-link-row>
</div>
</div>
......@@ -151,33 +161,40 @@ h1 {
</div>
<div id="nav">
<div id="navSeparator"></div>
<div id="navSeparator" hidden$="[[
shouldHideNavSeparator(activeScreen) ]]"></div>
<div id="navButtons">
<cr-button on-click="showPreviousLesson"
hidden$="[[
shouldHidePreviousLessonButton(activeLessonIndex, activeScreen) ]]">
[[ previousLesson ]]
</cr-button>
<cr-button on-click="showNextLesson"
hidden$="[[
shouldHideNextLessonButton(activeLessonIndex, activeScreen) ]]">
[[ nextLesson ]]
</cr-button>
<cr-button on-click="showLessonMenu"
hidden$="[[ shouldHideLessonMenuButton(activeScreen) ]]">
[[ lessonMenu ]]
</cr-button>
<cr-button on-click="showMainMenu"
hidden$="[[ shouldHideMainMenuButton(activeScreen) ]]">
[[ mainMenu ]]
</cr-button>
<cr-button on-click="showFirstLesson"
hidden$="[[
shouldHideRestartQuickOrientationButton(activeLessonIndex, activeScreen)
]]">
[[ restartQuickOrientation ]]
</cr-button>
<cr-button on-click="exit">[[ exitTutorial ]]</cr-button>
<div id="lessonNav">
<cr-button id="nextLesson" class="action-button" on-click="showNextLesson"
hidden$="[[
shouldHideNextLessonButton(activeLessonIndex, activeScreen) ]]">
[[ nextLesson ]]
</cr-button>
<cr-button on-click="showPreviousLesson"
hidden$="[[
shouldHidePreviousLessonButton(activeLessonIndex, activeScreen) ]]">
[[ previousLesson ]]
</cr-button>
</div>
<div id="menuNav">
<cr-button on-click="showFirstLesson"
hidden$="[[
shouldHideRestartQuickOrientationButton(activeLessonIndex, activeScreen)
]]">
[[ restartQuickOrientation ]]
</cr-button>
<cr-button on-click="showLessonMenu"
hidden$="[[ shouldHideLessonMenuButton(activeScreen) ]]">
[[ lessonMenu ]]
</cr-button>
<cr-button on-click="showMainMenu"
hidden$="[[ shouldHideMainMenuButton(activeScreen) ]]">
[[ mainMenu ]]
</cr-button>
<cr-button id="exitTutorial" on-click="exit">
[[ exitTutorial ]]
</cr-button>
</div>
</div>
</div>
......
......@@ -9,6 +9,9 @@
import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.m.js';
import 'chrome://resources/cr_elements/shared_style_css.m.js';
import 'chrome://resources/cr_elements/shared_vars_css.m.js';
import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {TutorialCommon} from './tutorial_common.js';
......@@ -346,56 +349,28 @@ Polymer({
content: ['tutorial_basic_navigation'],
medium: InteractionMedium.KEYBOARD,
curriculums: [Curriculum.NAVIGATION],
practiceTitle: 'Basic Navigation Practice',
practiceInstructions:
'Try using basic navigation to navigate through the items ' +
'below. Find the button titled "Click me" and use Search ' +
'+ Space to click it. Then move to the next lesson.',
practiceFile: 'basic_navigation',
practiceState: {
goal: {click: false},
},
events: ['click'],
hints: [
'Try pressing Search + left/right arrow. The search key is' +
' directly above the shift key',
'Press Search + Space to activate the current item.'
],
},
{
title: 'tutorial_jump_heading',
content: [
'tutorial_jump',
'tutorial_jump_second_heading',
'tutorial_jump_wrap_heading',
`Jump commands can be used to efficiently navigate through a web
page.`,
`Additional jump commands include jumping by link, button, and
checkbox, to name a few. A full list of jump commands can be
found in the ChromeVox menus, which can be opened by pressing
Search + Period.`,
],
medium: InteractionMedium.KEYBOARD,
curriculums: [Curriculum.NAVIGATION],
practiceTitle: 'Jump Commands Practice',
practiceInstructions:
'Try using what you have learned to navigate by element type. ' +
'Notice that navigation wraps if you are on the first or ' +
'last element and press previous element or next element, ' +
'respectively.',
'Try jumping by heading to navigate the text below',
practiceFile: 'jump_commands',
practiceState: {
'first-heading': {focus: false},
'first-link': {focus: false},
'first-button': {focus: false},
'second-heading': {focus: false},
'second-link': {focus: false},
'second-button': {focus: false},
'last-heading': {focus: false},
'last-link': {focus: false},
'last-button': {focus: false},
},
events: ['focus'],
hints: [
'Try using search + h to move by header',
'Try using search + b to move by button',
'Try using search + l to move by link'
],
practiceState: {},
events: [],
hints: []
},
{
......@@ -624,10 +599,11 @@ Polymer({
// Create shortcuts for each included lesson.
let count = 1;
for (const lesson of this.includedLessons) {
const button = document.createElement('cr-button');
button.addEventListener('click', this.showLesson.bind(this, count - 1));
button.textContent = this.getMsg(lesson.title);
this.$.lessonShortcuts.appendChild(button);
const shortcut = document.createElement('cr-link-row');
shortcut.addEventListener('click', this.showLesson.bind(this, count - 1));
shortcut.label = this.getMsg(lesson.title);
shortcut.classList.add('hr');
this.$.lessonShortcuts.appendChild(shortcut);
count += 1;
}
},
......@@ -716,6 +692,10 @@ Polymer({
return activeScreen !== Screen.LESSON_MENU;
},
shouldHideNavSeparator(activeScreen) {
return activeScreen !== Screen.LESSON;
},
/**
* @param {Curriculum} curriculum
* @return {string}
......
<!-- Copyright 2020 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<style>
<style include="md-select cr-shared-style">
:host {
--cr-dialog-width: 704px;
}
body,
div,
h1,
/** Font styling */
p,
cr-button,
a {
font-family: Google Sans;
font-family: 'Roboto';
}
#title {
font-family: 'Google Sans', 'Roboto';
}
#title,
#practiceTitle {
font-size: 32px;
font-weight: medium;
line-height: 40px;
margin-bottom: 16px;
}
#content {
display: block;
font-size: 28px;
font-style: normal;
font-weight: normal;
line-height: 36px;
margin: auto;
max-height: 500px;
max-height: 400px;
overflow: scroll;
text-align: center;
text-align: start
}
#practice {
overflow: scroll;
#content p,
#practiceInstructions,
#practiceBody {
color: black;
font-size: 22px;
font-weight: normal;
line-height: 28px;
margin-bottom: 16px;
margin-top: 0;
text-align: start
}
/* Practice area */
#practiceTitle {
font-size: 28px;
font-weight: 500;
font-family: 'Google Sans', 'Roboto';
}
#practiceInstructions {
line-height: 32px;
margin: 5px;
padding: 5px;
color: black;
}
#practiceBody {
color: #000;
font-size: 22px;
font-style: normal;
font-weight: normal;
padding: 20px;
text-align: center;
}
#practiceBody h1,
#practiceBody h2,
#practiceBody h3,
#practiceBody h4,
#practiceBody h5,
#practiceBody h6 {
margin: 5px;
display: flex;
flex-direction: column;
max-height: 400px;
overflow: auto;
}
#practiceContent cr-button {
font-size: 18px;
margin: 20px;
#practiceContent * {
display: block;
margin-bottom: 8px;
margin-top: 8px;
text-align: start;
}
#practiceContent a {
color: rgb(26, 115, 232);
font-size: 18px;
margin: 20px;
}
#startPractice {
color: rgb(26, 115, 232);
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 20px;
margin-bottom: 10px;
margin-inline-end: 10px;
margin-inline-start: 10px;
margin-top: 10px;
margin-bottom: 32px;
margin-inline-start: 0;
margin-top: 16px;
}
#separator {
background: rgb(232, 234, 237);
height: 1px;
margin: 20px;
#closePractice,
#startPractice {
font-size: 16px;
font-style: normal;
font-weight: medium;
line-height: 24px;
}
</style>
......@@ -105,16 +102,19 @@ a {
<p tabindex="-1">[[ getMsg(text) ]]</p>
</template>
</div>
<cr-dialog id="practice" close-text="Exit practice area"
on-close="endPractice" show-close-button>
<cr-dialog id="practice">
<div id="practiceTitle" class="title" slot="title" tabindex="-1">
[[ practiceTitle ]]
</div>
<div id="practiceBody" class="body" slot="body" tabindex="-1">
<p id="practiceInstructions" tabindex="-1">[[ practiceInstructions ]]</p>
<div id="separator"></div>
<div id="practiceContent"></div>
</div>
<div class="button-container" slot="button-container">
<cr-button id="closePractice" on-click="endPractice">
Close
</cr-button>
</div>
</cr-dialog>
<cr-button id="startPractice" on-click="startPractice"
hidden$="[[ shouldHidePracticeButton() ]]">Practice Area</cr-button>
......
......@@ -9,6 +9,9 @@
import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
import 'chrome://resources/cr_elements/md_select_css.m.js';
import 'chrome://resources/cr_elements/shared_style_css.m.js';
import 'chrome://resources/cr_elements/shared_vars_css.m.js';
import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {TutorialCommon} from './tutorial_common.js';
......@@ -167,6 +170,7 @@ export const TutorialLesson = Polymer({
/** @private */
endPractice() {
this.$.practice.close();
this.notifyEndPractice();
this.$.startPractice.focus();
},
......
<!-- Copyright 2020 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<script type="module"
src="chrome://resources/cr_elements/cr_button/cr_button.m.js">
</script>
<div style="white-space: pre">
<h3 id="first-heading" tabindex="-1">This is the first heading</h3>
<a id="first-link" href="#first-link">This is the first link</a>
<cr-button id="first-button">This is the first button</cr-button>
<h3 id="second-heading" tabindex="-1">This is the middle heading</h3>
<cr-button id="second-button">This is the second button</cr-button>
<a id="second-link" href="#second-link">This is the second link</a>
<cr-button id="last-button">This is the last button</cr-button>
<h3 id="last-heading" tabindex="-1">This is the last heading</h3>
<a id="last-link"href="#last-link">This is the last link</a>
</div>
<h5>This is the first heading. Press Search + H to go to the next heading</h5>
<h5>
This is the second heading. Keep going; either press Search+H or Search+Shift+H
</h5>
<h5>This is the last heading. Press Search+H to wrap to the first heading, or
Search+Shift+H to go to the second heading on this page.
</h5>
\ No newline at end of file
......@@ -2,9 +2,9 @@
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<label id="selectLabel">Choose your favorite season</label>
<select aria-labelledby="selectLabel">
<select class="md-select" aria-labelledby="selectLabel">
<option>Spring</option>
<option>Summer</option>
<option>Fall</option>
<option>Winter</option>
</select>
\ No newline at end of file
</select>
......@@ -122,17 +122,17 @@ TEST_F('ChromeVoxTutorialTest', 'BasicTest', function() {
'ChromeVox tutorial', 'Heading 1',
'Press Search + left/right arrow to browse topics')
.call(doCmd('nextObject'))
.expectSpeech('Quick orientation', 'Button')
.expectSpeech('Quick orientation', 'Link')
.call(doCmd('nextObject'))
.expectSpeech('Essential keys', 'Button')
.expectSpeech('Essential keys', 'Link')
.call(doCmd('nextObject'))
.expectSpeech('Navigation', 'Button')
.expectSpeech('Navigation', 'Link')
.call(doCmd('nextObject'))
.expectSpeech('Command references', 'Button')
.expectSpeech('Command references', 'Link')
.call(doCmd('nextObject'))
.expectSpeech('Sounds and settings', 'Button')
.expectSpeech('Sounds and settings', 'Link')
.call(doCmd('nextObject'))
.expectSpeech('Resources', 'Button')
.expectSpeech('Resources', 'Link')
.call(doCmd('nextObject'))
.expectSpeech('Exit tutorial', 'Button')
.replay();
......@@ -148,7 +148,7 @@ TEST_F('ChromeVoxTutorialTest', 'LessonSetTest', function() {
const tutorial = this.getPanel().iTutorial;
mockFeedback.expectSpeech('ChromeVox tutorial')
.call(doCmd('nextObject'))
.expectSpeech('Quick orientation', 'Button')
.expectSpeech('Quick orientation')
.call(doCmd('forceClickOnCurrentItem'))
.expectSpeech(/Quick Orientation Tutorial, [0-9]+ Lessons/)
.expectSpeech(
......@@ -163,9 +163,9 @@ TEST_F('ChromeVoxTutorialTest', 'LessonSetTest', function() {
})
.expectSpeech('ChromeVox tutorial')
.call(doCmd('nextObject'))
.expectSpeech('Quick orientation', 'Button')
.expectSpeech('Quick orientation')
.call(doCmd('nextObject'))
.expectSpeech('Essential keys', 'Button')
.expectSpeech('Essential keys', 'Link')
.call(doCmd('forceClickOnCurrentItem'))
.expectSpeech(/Essential Keys Tutorial, [0-9]+ Lessons/)
.call(doCmd('nextObject'))
......@@ -182,9 +182,9 @@ TEST_F('ChromeVoxTutorialTest', 'NoPracticeAreaTest', function() {
const tutorial = this.getPanel().iTutorial;
mockFeedback.expectSpeech('ChromeVox tutorial')
.call(doCmd('nextObject'))
.expectSpeech('Quick orientation', 'Button')
.expectSpeech('Quick orientation')
.call(doCmd('nextObject'))
.expectSpeech('Essential keys', 'Button')
.expectSpeech('Essential keys')
.call(doCmd('forceClickOnCurrentItem'))
.expectSpeech(/Essential Keys Tutorial, [0-9]+ Lessons/)
.call(() => {
......@@ -207,17 +207,17 @@ TEST_F('ChromeVoxTutorialTest', 'HasPracticeAreaTest', function() {
const tutorial = this.getPanel().iTutorial;
mockFeedback.expectSpeech('ChromeVox tutorial')
.call(doCmd('nextObject'))
.expectSpeech('Quick orientation', 'Button')
.expectSpeech('Quick orientation')
.call(doCmd('nextObject'))
.expectSpeech('Essential keys', 'Button')
.expectSpeech('Essential keys')
.call(doCmd('nextObject'))
.expectSpeech('Navigation', 'Button')
.expectSpeech('Navigation')
.call(doCmd('forceClickOnCurrentItem'))
.expectSpeech(/Navigation Tutorial, [0-9]+ Lessons/)
.call(() => {
tutorial.showLesson(0);
tutorial.showLesson(1);
})
.expectSpeech('Basic Navigation', 'Heading 1')
.expectSpeech('Jump Commands', 'Heading 1')
.call(doCmd('nextButton'))
.expectSpeech('Practice Area')
.replay();
......@@ -256,7 +256,7 @@ TEST_F('ChromeVoxTutorialTest', 'GeneralNudgesTest', function() {
// Tests nudges given in the practice area context. Note, each practice area
// can have different nudge messages; this test confirms that nudges given in
// the practice area differ from those given in the general tutorial context.
TEST_F('ChromeVoxTutorialTest', 'PracticeAreaNudgesTest', function() {
TEST_F('ChromeVoxTutorialTest', 'DISABLED_PracticeAreaNudgesTest', function() {
const mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.simpleDoc, async function(root) {
await this.launchAndWaitForTutorial();
......@@ -266,11 +266,11 @@ TEST_F('ChromeVoxTutorialTest', 'PracticeAreaNudgesTest', function() {
};
mockFeedback.expectSpeech('ChromeVox tutorial')
.call(doCmd('nextObject'))
.expectSpeech('Quick orientation', 'Button')
.expectSpeech('Quick orientation')
.call(doCmd('nextObject'))
.expectSpeech('Essential keys', 'Button')
.expectSpeech('Essential keys')
.call(doCmd('nextObject'))
.expectSpeech('Navigation', 'Button')
.expectSpeech('Navigation')
.call(doCmd('forceClickOnCurrentItem'))
.expectSpeech(/Navigation Tutorial, [0-9]+ Lessons/)
.call(() => {
......@@ -369,7 +369,7 @@ TEST_F('ChromeVoxTutorialTest', 'AllLessonsButton', function() {
.expectSpeech(/Essential Keys Tutorial, [0-9]+ Lessons/)
.call(this.assertActiveScreen.bind(this, 'lesson_menu'))
.call(doCmd('nextObject'))
.expectSpeech('On, Off, and Stop', 'Button')
.expectSpeech('On, Off, and Stop')
.call(doCmd('forceClickOnCurrentItem'))
.expectSpeech('On, Off, and Stop', 'Heading 1')
.call(this.assertActiveScreen.bind(this, 'lesson'))
......@@ -420,11 +420,11 @@ TEST_F('ChromeVoxTutorialTest', 'AutoReadTitle', function() {
const tutorial = this.getPanel().iTutorial;
mockFeedback.expectSpeech('ChromeVox tutorial')
.call(doCmd('nextObject'))
.expectSpeech('Quick orientation', 'Button')
.expectSpeech('Quick orientation')
.call(doCmd('forceClickOnCurrentItem'))
.expectSpeech(/Quick Orientation Tutorial, [0-9]+ Lessons/)
.call(doCmd('nextObject'))
.expectSpeech('Welcome to ChromeVox!', 'Button')
.expectSpeech('Welcome to ChromeVox!')
.call(doCmd('forceClickOnCurrentItem'))
.expectSpeech('Welcome to ChromeVox!')
.expectSpeech(
......@@ -445,9 +445,9 @@ TEST_F('ChromeVoxTutorialTest', 'LessonHint', function() {
const tutorial = this.getPanel().iTutorial;
mockFeedback.expectSpeech('ChromeVox tutorial')
.call(doCmd('nextObject'))
.expectSpeech('Quick orientation', 'Button')
.expectSpeech('Quick orientation')
.call(doCmd('nextObject'))
.expectSpeech('Essential keys', 'Button')
.expectSpeech('Essential keys')
.call(doCmd('forceClickOnCurrentItem'))
.expectSpeech(/Essential Keys Tutorial, [0-9]+ Lessons/)
.call(() => {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment