55import * as Common from '../../core/common/common.js' ;
66import * as Host from '../../core/host/host.js' ;
77import type * as Platform from '../../core/platform/platform.js' ;
8+ import type { LocalizedString } from '../../core/platform/UIString.js' ;
89import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js' ;
910import { renderElementIntoDOM } from '../../testing/DOMHelpers.js' ;
1011import { describeWithEnvironment , updateHostConfig } from '../../testing/EnvironmentHelpers.js' ;
12+ import { createViewFunctionStub , type ViewFunctionStub } from '../../testing/ViewFunctionHelpers.js' ;
1113import * as Switch from '../../ui/components/switch/switch.js' ;
1214
1315import * as Settings from './settings.js' ;
1416
15- async function drainMicroTasks ( ) {
16- await new Promise ( resolve => setTimeout ( resolve , 0 ) ) ;
17- }
18-
1917describeWithEnvironment ( 'AISettingsTab' , ( ) => {
2018 let deleteAiAssistanceHistoryStub :
2119 sinon . SinonStub < Parameters < typeof AiAssistanceModel . AiHistoryStorage . AiHistoryStorage . prototype . deleteAll > > ;
22- let view : Settings . AISettingsTab . AISettingsTab | undefined ;
20+ let aidaAccessStub : sinon . SinonStub < [ ] , Promise < Host . AidaClient . AidaAccessPreconditions > > ;
2321
2422 beforeEach ( async ( ) => {
2523 deleteAiAssistanceHistoryStub =
@@ -33,11 +31,12 @@ describeWithEnvironment('AISettingsTab', () => {
3331 enabled : true ,
3432 }
3533 } ) ;
34+ aidaAccessStub = sinon . stub ( Host . AidaClient . AidaClient , 'checkAccessPreconditions' ) ;
35+ aidaAccessStub . returns ( Promise . resolve ( Host . AidaClient . AidaAccessPreconditions . AVAILABLE ) ) ;
3636 } ) ;
3737
3838 afterEach ( async ( ) => {
39- await drainMicroTasks ( ) ;
40- view ?. remove ( ) ;
39+ aidaAccessStub . restore ( ) ;
4140 } ) ;
4241
4342 function mockHostConfigWithExplainThisResourceEnabled ( ) {
@@ -49,72 +48,48 @@ describeWithEnvironment('AISettingsTab', () => {
4948 } ) ;
5049 }
5150
52- function isExpanded ( details : Element ) : boolean {
53- return details . classList . contains ( 'open' ) ;
54- }
55-
56- async function renderAISettings ( ) : Promise < {
57- switches : Switch . Switch . Switch [ ] ,
58- details : Element [ ] ,
59- dropdownButtons : HTMLElement [ ] ,
60- toggleContainers : HTMLElement [ ] ,
61- view : Settings . AISettingsTab . AISettingsTab ,
51+ async function setupWidget ( ) : Promise < {
52+ widget : Settings . AISettingsTab . AISettingsTab ,
53+ view : ViewFunctionStub < typeof Settings . AISettingsTab . AISettingsTab > ,
6254 } > {
63- Common . Settings . moduleSetting ( 'console-insights-enabled' ) . set ( false ) ;
64- Common . Settings . moduleSetting ( 'ai-assistance-enabled' ) . set ( true ) ;
65- Common . Settings . moduleSetting ( 'ai-annotations-enabled' ) . set ( true ) ;
66- Common . Settings . moduleSetting ( 'ai-code-completion-enabled' ) . set ( false ) ;
67-
68- view = new Settings . AISettingsTab . AISettingsTab ( ) ;
69- renderElementIntoDOM ( view ) ;
70- await view . render ( ) ;
71- assert . isNotNull ( view . shadowRoot ) ;
72-
73- const switches = Array . from ( view . shadowRoot . querySelectorAll ( 'devtools-switch' ) ) ;
74- assert . lengthOf ( switches , 4 ) ;
75- const details = Array . from ( view . shadowRoot . querySelectorAll ( '.whole-row' ) ) ;
76- assert . lengthOf ( details , 4 ) ;
77- const dropdownButtons = Array . from ( view . shadowRoot . querySelectorAll ( '.dropdown devtools-button' ) ) as HTMLElement [ ] ;
78- assert . lengthOf ( dropdownButtons , 4 ) ;
79- const toggleContainers =
80- Array . from ( view . shadowRoot . querySelectorAll ( '.toggle-container' ) ) as Switch . Switch . Switch [ ] ;
81- assert . lengthOf ( toggleContainers , 4 ) ;
82- return { switches, details, dropdownButtons, toggleContainers, view} ;
55+ const view = createViewFunctionStub ( Settings . AISettingsTab . AISettingsTab ) ;
56+ const widget = new Settings . AISettingsTab . AISettingsTab ( view ) ;
57+ const container = document . createElement ( 'div' ) ;
58+ renderElementIntoDOM ( container ) ;
59+ widget . markAsRoot ( ) ;
60+ widget . show ( container ) ;
61+ await view . nextInput ;
62+ return { widget, view} ;
8363 }
8464
85- it ( 'renders' , async ( ) => {
65+ it ( 'renders disclaimers and settings ' , async ( ) => {
8666 Common . Settings . moduleSetting ( 'console-insights-enabled' ) . set ( true ) ;
8767 Common . Settings . moduleSetting ( 'ai-assistance-enabled' ) . set ( true ) ;
8868 Common . Settings . moduleSetting ( 'ai-annotations-enabled' ) . set ( true ) ;
8969 Common . Settings . moduleSetting ( 'ai-code-completion-enabled' ) . set ( true ) ;
9070
91- view = new Settings . AISettingsTab . AISettingsTab ( ) ;
92- renderElementIntoDOM ( view ) ;
93- await view . render ( ) ;
94- assert . isNotNull ( view . shadowRoot ) ;
71+ const { view} = await setupWidget ( ) ;
9572
96- const sharedDisclaimerHeader = view . shadowRoot . querySelector ( '.shared-disclaimer h2' ) ;
97- assert . strictEqual ( sharedDisclaimerHeader ?. textContent , 'Boost your productivity with AI' ) ;
98-
99- const disclaimers = view . shadowRoot . querySelectorAll ( '.shared-disclaimer .disclaimer-list div' ) ;
73+ const disclaimers = view . input . sharedDisclaimerBulletPoints ;
74+ const sendDataDiscalimer = disclaimers [ 1 ] . text as LocalizedString ;
10075 assert . strictEqual (
101- disclaimers [ 3 ] . textContent ,
76+ sendDataDiscalimer ,
10277 'These features send relevant data to Google. Google collects this data and feedback to improve its products and services with the help of human reviewers. Avoid sharing sensitive or personal information.' ) ;
103- assert . strictEqual ( disclaimers [ 5 ] . textContent , 'Depending on your region, Google may refrain from data collection' ) ;
78+ const dataCollectionDiscalimer = disclaimers [ 2 ] . text as LocalizedString ;
79+ assert . strictEqual ( dataCollectionDiscalimer , 'Depending on your region, Google may refrain from data collection' ) ;
10480
105- const settingCards = view . shadowRoot . querySelectorAll ( '.setting-card h2' ) ;
106- const settingNames = Array . from ( settingCards ) . map ( element => element . textContent ) ;
81+ const settingToParams = view . input . settingToParams ;
82+ const settingParams = Array . from ( settingToParams . values ( ) ) ;
83+ const settingNames = settingParams . map ( setting => setting . settingName ) ;
10784 assert . deepEqual ( settingNames , [ 'Console Insights' , 'AI assistance' , 'Auto annotations' , 'Code suggestions' ] ) ;
108-
109- const settingCardDesc = view . shadowRoot . querySelectorAll ( '.setting-description' ) ;
110- assert . strictEqual ( settingCardDesc [ 0 ] . textContent , 'Helps you understand and fix console warnings and errors' ) ;
111- assert . strictEqual ( settingCardDesc [ 1 ] . textContent , 'Get help with understanding CSS styles' ) ;
85+ assert . strictEqual ( settingParams [ 0 ] . settingDescription , 'Helps you understand and fix console warnings and errors' ) ;
86+ assert . strictEqual ( settingParams [ 1 ] . settingDescription , 'Get help with understanding CSS styles' ) ;
11287 assert . strictEqual (
113- settingCardDesc [ 2 ] . textContent , 'Automatically generate titles for performance trace annotations' ) ;
114- assert . strictEqual ( settingCardDesc [ 3 ] . textContent , 'Get help completing your code' ) ;
88+ settingParams [ 2 ] . settingDescription , 'Automatically generate titles for performance trace annotations' ) ;
89+ assert . strictEqual ( settingParams [ 3 ] . settingDescription , 'Get help completing your code' ) ;
11590 } ) ;
11691
117- it ( 'renders different dislaimers for managed users which have logging disabled' , async ( ) => {
92+ it ( 'has different dislaimers for managed users which have logging disabled' , async ( ) => {
11893 Common . Settings . moduleSetting ( 'console-insights-enabled' ) . set ( true ) ;
11994 Common . Settings . moduleSetting ( 'ai-assistance-enabled' ) . set ( true ) ;
12095 Common . Settings . moduleSetting ( 'ai-annotations-enabled' ) . set ( true ) ;
@@ -130,73 +105,88 @@ describeWithEnvironment('AISettingsTab', () => {
130105 } ,
131106 } ) ;
132107
133- view = new Settings . AISettingsTab . AISettingsTab ( ) ;
134- renderElementIntoDOM ( view ) ;
135- await view . render ( ) ;
136- assert . isNotNull ( view . shadowRoot ) ;
108+ const { view} = await setupWidget ( ) ;
137109
138- const disclaimers = view . shadowRoot . querySelectorAll ( '.shared-disclaimer .disclaimer-list div' ) ;
110+ const disclaimers = view . input . sharedDisclaimerBulletPoints ;
111+ const sendDataNoLogging = disclaimers [ 1 ] . text as LocalizedString ;
139112 assert . strictEqual (
140- disclaimers [ 3 ] . textContent ,
113+ sendDataNoLogging ,
141114 'Your content will not be used by human reviewers to improve AI. Your organization may change these settings at any time.' ) ;
115+ const dataCollectionNoLogging = disclaimers [ 2 ] . text as LocalizedString ;
142116 assert . strictEqual (
143- disclaimers [ 5 ] . textContent ,
117+ dataCollectionNoLogging ,
144118 'Depending on your Google account management and/or region, Google may refrain from data collection' ) ;
145119 } ) ;
146120
147- it ( 'renders with explain this resource enabled' , async ( ) => {
148- mockHostConfigWithExplainThisResourceEnabled ( ) ;
121+ it ( 'has explain this resource enabled' , async ( ) => {
149122 Common . Settings . moduleSetting ( 'console-insights-enabled' ) . set ( true ) ;
150123 Common . Settings . moduleSetting ( 'ai-assistance-enabled' ) . set ( true ) ;
124+ mockHostConfigWithExplainThisResourceEnabled ( ) ;
151125
152- view = new Settings . AISettingsTab . AISettingsTab ( ) ;
153- renderElementIntoDOM ( view ) ;
154- await view . render ( ) ;
155- assert . isNotNull ( view . shadowRoot ) ;
126+ const { view} = await setupWidget ( ) ;
156127
157- const settingCardDesc = view . shadowRoot . querySelectorAll ( '.setting-description' ) ;
158- assert . strictEqual ( settingCardDesc [ 1 ] . textContent , 'Get help with understanding CSS styles, and network requests' ) ;
128+ const settingToParams = view . input . settingToParams . entries ( ) ;
129+ settingToParams . next ( ) ;
130+ const explainThisResource = settingToParams . next ( ) ;
131+ assert . exists ( explainThisResource . value ) ;
132+ assert . isFalse ( explainThisResource . value [ 0 ] . disabled ( ) ) ;
133+ assert . strictEqual (
134+ explainThisResource . value [ 1 ] . settingDescription ,
135+ 'Get help with understanding CSS styles, and network requests' ) ;
159136 } ) ;
160137
161138 it ( 'can turn feature on, which automatically expands it' , async ( ) => {
162- const { switches, details} = await renderAISettings ( ) ;
139+ Common . Settings . moduleSetting ( 'console-insights-enabled' ) . set ( false ) ;
140+ const { view} = await setupWidget ( ) ;
141+
163142 assert . isFalse ( Common . Settings . moduleSetting ( 'console-insights-enabled' ) . get ( ) ) ;
164- assert . isFalse ( isExpanded ( details [ 0 ] ) ) ;
143+ const setting = view . input . settingToParams . entries ( ) . next ( ) ;
144+ assert . exists ( setting . value ) ;
145+ assert . isFalse ( setting . value [ 1 ] . settingExpandState . isSettingExpanded ) ;
165146
166- switches [ 0 ] . dispatchEvent ( new Switch . Switch . SwitchChangeEvent ( true ) ) ;
147+ view . input . toggleSetting ( setting . value [ 0 ] , new Switch . Switch . SwitchChangeEvent ( true ) ) ;
167148 assert . isTrue ( Common . Settings . moduleSetting ( 'console-insights-enabled' ) . get ( ) ) ;
168- assert . isTrue ( isExpanded ( details [ 0 ] ) ) ;
149+ assert . isTrue ( setting . value [ 1 ] . settingExpandState . isSettingExpanded ) ;
169150 } ) ;
170151
171- it ( 'can expand and collaps details via click' , async ( ) => {
172- const { details, dropdownButtons} = await renderAISettings ( ) ;
173- assert . isFalse ( isExpanded ( details [ 0 ] ) ) ;
152+ it ( 'can expand and collapse details via click' , async ( ) => {
153+ Common . Settings . moduleSetting ( 'console-insights-enabled' ) . set ( false ) ;
154+ const { view} = await setupWidget ( ) ;
155+
156+ const setting = view . input . settingToParams . entries ( ) . next ( ) ;
157+ assert . exists ( setting . value ) ;
158+ assert . isFalse ( setting . value [ 1 ] . settingExpandState . isSettingExpanded ) ;
174159 assert . isFalse ( Common . Settings . moduleSetting ( 'console-insights-enabled' ) . get ( ) ) ;
175160
176- dropdownButtons [ 0 ] . click ( ) ;
177- assert . isTrue ( isExpanded ( details [ 0 ] ) ) ;
161+ view . input . expandSetting ( setting . value [ 0 ] ) ;
178162 assert . isFalse ( Common . Settings . moduleSetting ( 'console-insights-enabled' ) . get ( ) ) ;
163+ assert . isTrue ( setting . value [ 1 ] . settingExpandState . isSettingExpanded ) ;
179164
180- dropdownButtons [ 0 ] . click ( ) ;
181- assert . isFalse ( isExpanded ( details [ 0 ] ) ) ;
165+ view . input . expandSetting ( setting . value [ 0 ] ) ;
182166 assert . isFalse ( Common . Settings . moduleSetting ( 'console-insights-enabled' ) . get ( ) ) ;
167+ assert . isFalse ( setting . value [ 1 ] . settingExpandState . isSettingExpanded ) ;
183168 } ) ;
184169
185170 it ( 'can turn feature off without collapsing it' , async ( ) => {
186- const { switches, details, dropdownButtons} = await renderAISettings ( ) ;
187- dropdownButtons [ 1 ] . click ( ) ;
171+ Common . Settings . moduleSetting ( 'ai-assistance-enabled' ) . set ( true ) ;
172+ const { view} = await setupWidget ( ) ;
173+
174+ const settingToParams = view . input . settingToParams . entries ( ) ;
175+ settingToParams . next ( ) ;
176+ const setting = settingToParams . next ( ) ;
177+ assert . exists ( setting . value ) ;
178+
179+ view . input . expandSetting ( setting . value [ 0 ] ) ;
188180 assert . isTrue ( Common . Settings . moduleSetting ( 'ai-assistance-enabled' ) . get ( ) ) ;
189- assert . isTrue ( isExpanded ( details [ 1 ] ) ) ;
181+ assert . isTrue ( setting . value [ 1 ] . settingExpandState . isSettingExpanded ) ;
190182
191- ( switches [ 1 ] . parentElement as HTMLElement ) . click ( ) ;
183+ view . input . toggleSetting ( setting . value [ 0 ] , new MouseEvent ( 'click' ) ) ;
192184 assert . isFalse ( Common . Settings . moduleSetting ( 'ai-assistance-enabled' ) . get ( ) ) ;
193- assert . isTrue ( isExpanded ( details [ 1 ] ) ) ;
185+ assert . isTrue ( setting . value [ 1 ] . settingExpandState . isSettingExpanded ) ;
194186 } ) ;
195187
196188 it ( 'disables switches if blocked by age' , async ( ) => {
197189 const underAgeExplainer = 'This feature is only available to users who are 18 years of age or older.' ;
198- const aidaAccessStub = sinon . stub ( Host . AidaClient . AidaClient , 'checkAccessPreconditions' ) ;
199- aidaAccessStub . returns ( Promise . resolve ( Host . AidaClient . AidaAccessPreconditions . AVAILABLE ) ) ;
200190 updateHostConfig ( {
201191 aidaAvailability : {
202192 blockedByAge : true ,
@@ -209,50 +199,28 @@ describeWithEnvironment('AISettingsTab', () => {
209199 } ,
210200 } ) ;
211201
212- const { switches, toggleContainers, view} = await renderAISettings ( ) ;
213- assert . strictEqual ( view . shadowRoot ?. querySelector ( '.disabled-explainer' ) ?. textContent ?. trim ( ) , underAgeExplainer ) ;
214- assert . isTrue ( switches [ 0 ] . disabled ) ;
215- assert . strictEqual ( toggleContainers [ 0 ] . title , underAgeExplainer ) ;
216- assert . isTrue ( switches [ 1 ] . disabled ) ;
217- assert . strictEqual ( toggleContainers [ 1 ] . title , underAgeExplainer ) ;
218- assert . isTrue ( switches [ 2 ] . disabled ) ;
219- assert . strictEqual ( toggleContainers [ 2 ] . title , underAgeExplainer ) ;
220- assert . isTrue ( switches [ 3 ] . disabled ) ;
221- assert . strictEqual ( toggleContainers [ 3 ] . title , underAgeExplainer ) ;
202+ const { view} = await setupWidget ( ) ;
222203
223- aidaAccessStub . restore ( ) ;
204+ assert . deepEqual ( view . input . disabledReasons , [ underAgeExplainer ] ) ;
224205 } ) ;
225206
226207 it ( 'updates when the user logs in' , async ( ) => {
227208 const notLoggedInExplainer = 'This feature is only available when you sign into Chrome with your Google account.' ;
228- const aidaAccessStub = sinon . stub ( Host . AidaClient . AidaClient , 'checkAccessPreconditions' ) ;
229209 aidaAccessStub . returns ( Promise . resolve ( Host . AidaClient . AidaAccessPreconditions . NO_ACCOUNT_EMAIL ) ) ;
230210
231- const { switches, toggleContainers, view} = await renderAISettings ( ) ;
232- assert . strictEqual (
233- view . shadowRoot ?. querySelector ( '.disabled-explainer' ) ?. textContent ?. trim ( ) , notLoggedInExplainer ) ;
234- assert . isTrue ( switches [ 0 ] . disabled ) ;
235- assert . strictEqual ( toggleContainers [ 0 ] . title , notLoggedInExplainer ) ;
236- assert . isTrue ( switches [ 1 ] . disabled ) ;
237- assert . strictEqual ( toggleContainers [ 1 ] . title , notLoggedInExplainer ) ;
238- assert . isTrue ( switches [ 2 ] . disabled ) ;
239- assert . strictEqual ( toggleContainers [ 2 ] . title , notLoggedInExplainer ) ;
240- assert . isTrue ( switches [ 3 ] . disabled ) ;
241- assert . strictEqual ( toggleContainers [ 3 ] . title , notLoggedInExplainer ) ;
211+ const { view} = await setupWidget ( ) ;
212+
213+ assert . deepEqual ( view . input . disabledReasons , [ notLoggedInExplainer ] ) ;
242214
243215 aidaAccessStub . returns ( Promise . resolve ( Host . AidaClient . AidaAccessPreconditions . AVAILABLE ) ) ;
244216 Host . AidaClient . HostConfigTracker . instance ( ) . dispatchEventToListeners (
245217 Host . AidaClient . Events . AIDA_AVAILABILITY_CHANGED ) ;
246- await drainMicroTasks ( ) ;
247- assert . isNull ( view . shadowRoot ?. querySelector ( '.disabled-explainer' ) ) ;
248- assert . isFalse ( switches [ 0 ] . disabled ) ;
249- assert . isFalse ( switches [ 1 ] . disabled ) ;
250- assert . isFalse ( switches [ 2 ] . disabled ) ;
251- assert . isFalse ( switches [ 3 ] . disabled ) ;
252- aidaAccessStub . restore ( ) ;
218+ await view . nextInput ;
219+
220+ assert . deepEqual ( view . input . disabledReasons , [ ] ) ;
253221 } ) ;
254222
255- it ( 'renders disabled switch component with reason' , async ( ) => {
223+ it ( 'updates disabled reason' , async ( ) => {
256224 Common . Settings . moduleSetting ( 'console-insights-enabled' ) . setRegistration ( {
257225 settingName : 'console-insights-enabled' ,
258226 settingType : Common . Settings . SettingType . BOOLEAN ,
@@ -269,24 +237,23 @@ describeWithEnvironment('AISettingsTab', () => {
269237 return { disabled : true , reasons : [ 'some reason' as Platform . UIString . LocalizedString ] } ;
270238 } ,
271239 } ) ;
272- const stub = sinon . stub ( Host . AidaClient . AidaClient , 'checkAccessPreconditions' ) ;
273- stub . returns ( Promise . resolve ( Host . AidaClient . AidaAccessPreconditions . AVAILABLE ) ) ;
274-
275- const { switches, toggleContainers, view} = await renderAISettings ( ) ;
276- assert . strictEqual ( view . shadowRoot ?. querySelector ( '.disabled-explainer' ) ?. textContent ?. trim ( ) , 'some reason' ) ;
277- assert . isTrue ( switches [ 0 ] . disabled ) ;
278- assert . strictEqual ( toggleContainers [ 0 ] . title , 'some reason' ) ;
279- assert . isTrue ( switches [ 1 ] . disabled ) ;
280- assert . strictEqual ( toggleContainers [ 1 ] . title , 'some reason' ) ;
281- stub . restore ( ) ;
240+
241+ const { view} = await setupWidget ( ) ;
242+
243+ assert . deepEqual ( view . input . disabledReasons , [ 'some reason' ] ) ;
282244 } ) ;
283245
284246 it ( 'can turn feature off and clear history' , async ( ) => {
285- const { switches} = await renderAISettings ( ) ;
286247 Common . Settings . moduleSetting ( 'ai-assistance-enabled' ) . set ( true ) ;
287248 Common . Settings . moduleSetting ( 'ai-assistance-history-entries' ) . set ( [ { } , { } ] ) ;
249+ const { view} = await setupWidget ( ) ;
250+
251+ const settingToParams = view . input . settingToParams . entries ( ) ;
252+ settingToParams . next ( ) ;
253+ const setting = settingToParams . next ( ) ;
254+ assert . exists ( setting . value ) ;
288255
289- ( switches [ 1 ] . parentElement as HTMLElement ) . click ( ) ;
256+ view . input . toggleSetting ( setting . value [ 0 ] , new MouseEvent ( 'click' ) ) ;
290257 assert . isFalse ( Common . Settings . moduleSetting ( 'ai-assistance-enabled' ) . get ( ) ) ;
291258 assert . isTrue (
292259 deleteAiAssistanceHistoryStub . called , 'Expected AiHistoryStorage deleteAll to be called but it is not called' ) ;
0 commit comments