Skip to content

Commit 14997ad

Browse files
committed
Add support for handling option preferences
This additional feature for handling option preferences is a prerequisite for fixing #10891 Change-Id: I1cabb47ff21ab912ae8794c63d16143de9dc77e9
1 parent acd6f57 commit 14997ad

File tree

2 files changed

+109
-81
lines changed

2 files changed

+109
-81
lines changed

examples/playwright/src/theia-preference-view.ts

Lines changed: 75 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ const TheiaSettingsViewData = {
2424
};
2525

2626
export const PreferenceIds = {
27+
Editor: {
28+
AutoSave: 'editor.autoSave',
29+
RenderWhitespace: 'editor.renderWhitespace'
30+
},
2731
Explorer: {
2832
AutoReveal: 'explorer.autoReveal'
2933
},
@@ -33,6 +37,19 @@ export const PreferenceIds = {
3337
};
3438

3539
export const DefaultPreferences = {
40+
Editor: {
41+
AutoSave: {
42+
On: 'on',
43+
Off: 'off'
44+
},
45+
RenderWhitespace: {
46+
None: 'none',
47+
Boundary: 'boundary',
48+
Selection: 'selection',
49+
Trailing: 'trailing',
50+
All: 'all'
51+
}
52+
},
3653
Explorer: {
3754
AutoReveal: {
3855
Enabled: true
@@ -50,6 +67,7 @@ export enum TheiaPreferenceScope {
5067

5168
export class TheiaPreferenceView extends TheiaView {
5269
public customTimeout?: number;
70+
protected modificationIndicator = '.theia-mod-item-modified';
5371

5472
constructor(app: TheiaApp) {
5573
super(TheiaSettingsViewData, app);
@@ -72,98 +90,81 @@ export class TheiaPreferenceView extends TheiaView {
7290
await scopeTab.click();
7391
}
7492

93+
async getBooleanPreferenceByPath(sectionTitle: string, name: string): Promise<boolean> {
94+
const preferenceId = await this.findPreferenceId(sectionTitle, name);
95+
return this.getBooleanPreferenceById(preferenceId);
96+
}
97+
7598
async getBooleanPreferenceById(preferenceId: string): Promise<boolean> {
7699
const element = await this.findPreferenceEditorById(preferenceId);
77100
return element.isChecked();
78101
}
79102

80-
async getBooleanPreferenceByPath(sectionTitle: string, name: string): Promise<boolean> {
103+
async setBooleanPreferenceByPath(sectionTitle: string, name: string, value: boolean): Promise<void> {
81104
const preferenceId = await this.findPreferenceId(sectionTitle, name);
82-
return this.getBooleanPreferenceById(preferenceId);
105+
return this.setBooleanPreferenceById(preferenceId, value);
83106
}
84107

85108
async setBooleanPreferenceById(preferenceId: string, value: boolean): Promise<void> {
86109
const element = await this.findPreferenceEditorById(preferenceId);
87110
return value ? element.check() : element.uncheck();
88111
}
89112

90-
async setBooleanPreferenceByPath(sectionTitle: string, name: string, value: boolean): Promise<void> {
113+
async getStringPreferenceByPath(sectionTitle: string, name: string): Promise<string> {
91114
const preferenceId = await this.findPreferenceId(sectionTitle, name);
92-
return this.setBooleanPreferenceById(preferenceId, value);
115+
return this.getStringPreferenceById(preferenceId);
93116
}
94117

95118
async getStringPreferenceById(preferenceId: string): Promise<string> {
96119
const element = await this.findPreferenceEditorById(preferenceId);
97120
return element.evaluate(e => (e as HTMLInputElement).value);
98121
}
99122

100-
async getStringPreferenceByPath(sectionTitle: string, name: string): Promise<string> {
123+
async setStringPreferenceByPath(sectionTitle: string, name: string, value: string): Promise<void> {
101124
const preferenceId = await this.findPreferenceId(sectionTitle, name);
102-
return this.getStringPreferenceById(preferenceId);
125+
return this.setStringPreferenceById(preferenceId, value);
103126
}
104127

105128
async setStringPreferenceById(preferenceId: string, value: string): Promise<void> {
106129
const element = await this.findPreferenceEditorById(preferenceId);
107130
return element.fill(value);
108131
}
109132

110-
async setStringPreferenceByPath(sectionTitle: string, name: string, value: string): Promise<void> {
133+
async getOptionsPreferenceByPath(sectionTitle: string, name: string): Promise<string> {
111134
const preferenceId = await this.findPreferenceId(sectionTitle, name);
112-
return this.setStringPreferenceById(preferenceId, value);
135+
return this.getOptionsPreferenceById(preferenceId);
113136
}
114137

115-
async waitForModified(preferenceId: string): Promise<void> {
116-
await this.activate();
117-
const viewElement = await this.viewElement();
118-
await viewElement?.waitForSelector(`${this.getPreferenceGutterSelector(preferenceId)}.theia-mod-item-modified`, { timeout: this.customTimeout });
138+
async getOptionsPreferenceById(preferenceId: string): Promise<string> {
139+
const element = await this.findPreferenceEditorById(preferenceId, 'select');
140+
return element.evaluate(e => {
141+
const selectElement = (e as HTMLSelectElement);
142+
const option = selectElement.options[selectElement.selectedIndex];
143+
return option.text;
144+
});
119145
}
120146

121-
async resetStringPreferenceById(preferenceId: string): Promise<void> {
122-
const resetPreferenceButton = await this.findPreferenceResetButton(preferenceId);
123-
if (!resetPreferenceButton) {
124-
// preference not modified
125-
return;
126-
}
127-
const previousValue = await this.getStringPreferenceById(preferenceId);
128-
const selector = this.getPreferenceEditorSelector(preferenceId);
129-
const done = await resetPreferenceButton.click();
130-
await this.page.waitForFunction(data => {
131-
const element = document.querySelector(data.selector);
132-
if (!element) {
133-
throw new Error(`Could not find preference element with id "${data.preferenceId}"`);
134-
}
135-
const value = (element as HTMLInputElement).value;
136-
return value !== data.previousValue;
137-
}, { preferenceId, selector, previousValue, done }, { timeout: this.customTimeout });
138-
}
139-
140-
async resetStringPreferenceByPath(sectionTitle: string, name: string): Promise<void> {
147+
async setOptionsPreferenceByPath(sectionTitle: string, name: string, value: string): Promise<void> {
141148
const preferenceId = await this.findPreferenceId(sectionTitle, name);
142-
return this.resetStringPreferenceById(preferenceId);
149+
return this.setOptionsPreferenceById(preferenceId, value);
143150
}
144151

145-
async resetBooleanPreferenceById(preferenceId: string): Promise<void> {
146-
const resetPreferenceButton = await this.findPreferenceResetButton(preferenceId);
147-
if (!resetPreferenceButton) {
148-
// preference not modified
149-
return;
150-
}
151-
const previousValue = await this.getBooleanPreferenceById(preferenceId);
152-
const selector = this.getPreferenceEditorSelector(preferenceId);
153-
const done = await resetPreferenceButton.click();
154-
await this.page.waitForFunction(data => {
155-
const element = document.querySelector(data.selector);
156-
if (!element) {
157-
throw new Error(`Could not find preference element with id "${data.preferenceId}"`);
158-
}
159-
const value = (element as HTMLInputElement).checked;
160-
return value !== data.previousValue;
161-
}, { preferenceId, selector, previousValue, done }, { timeout: this.customTimeout });
162-
}
163-
164-
async resetBooleanPreferenceByPath(sectionTitle: string, name: string): Promise<void> {
152+
async setOptionsPreferenceById(preferenceId: string, value: string): Promise<void> {
153+
const element = await this.findPreferenceEditorById(preferenceId, 'select');
154+
await element.selectOption({ label: value });
155+
}
156+
157+
async resetPreferenceByPath(sectionTitle: string, name: string): Promise<void> {
165158
const preferenceId = await this.findPreferenceId(sectionTitle, name);
166-
return this.resetBooleanPreferenceById(preferenceId);
159+
return this.resetPreferenceById(preferenceId);
160+
}
161+
162+
async resetPreferenceById(preferenceId: string): Promise<void> {
163+
// this is just to fail if the preference doesn't exist at all
164+
await this.findPreferenceEditorById(preferenceId, '');
165+
const resetPreferenceButton = await this.findPreferenceResetButton(preferenceId);
166+
await resetPreferenceButton.click();
167+
await this.waitForUnmodified(preferenceId);
167168
}
168169

169170
private async findPreferenceId(sectionTitle: string, name: string): Promise<string> {
@@ -178,9 +179,9 @@ export class TheiaPreferenceView extends TheiaView {
178179
return preferenceId;
179180
}
180181

181-
private async findPreferenceEditorById(preferenceId: string): Promise<ElementHandle<SVGElement | HTMLElement>> {
182+
private async findPreferenceEditorById(preferenceId: string, elementType: string = 'input'): Promise<ElementHandle<SVGElement | HTMLElement>> {
182183
const viewElement = await this.viewElement();
183-
const element = await viewElement?.waitForSelector(this.getPreferenceEditorSelector(preferenceId), { timeout: this.customTimeout });
184+
const element = await viewElement?.waitForSelector(this.getPreferenceEditorSelector(preferenceId, elementType), { timeout: this.customTimeout });
184185
if (!element) {
185186
throw new Error(`Could not find element with preference id "${preferenceId}"`);
186187
}
@@ -191,26 +192,13 @@ export class TheiaPreferenceView extends TheiaView {
191192
return `li[data-pref-id="${preferenceId}"]`;
192193
}
193194

194-
private getPreferenceEditorSelector(preferenceId: string): string {
195-
return `${this.getPreferenceSelector(preferenceId)} input`;
195+
private getPreferenceEditorSelector(preferenceId: string, elementType: string): string {
196+
return `${this.getPreferenceSelector(preferenceId)} ${elementType}`;
196197
}
197198

198-
private getPreferenceGutterSelector(preferenceId: string): string {
199-
return `${this.getPreferenceSelector(preferenceId)} .pref-context-gutter`;
200-
}
201-
202-
private async findPreferenceResetButton(preferenceId: string): Promise<ElementHandle<SVGElement | HTMLElement> | undefined> {
199+
private async findPreferenceResetButton(preferenceId: string): Promise<ElementHandle<SVGElement | HTMLElement>> {
203200
await this.activate();
204201
const viewElement = await this.viewElement();
205-
const gutter = await viewElement?.waitForSelector(`${this.getPreferenceGutterSelector(preferenceId)}`, { timeout: this.customTimeout });
206-
if (!gutter) {
207-
throw new Error(`Could not determine modified state for element with preference id "${preferenceId}"`);
208-
}
209-
const isModified = await gutter.evaluate(e => e.classList.contains('theia-mod-item-modified'));
210-
if (!isModified) {
211-
return undefined;
212-
}
213-
214202
const settingsContextMenuBtn = await viewElement?.waitForSelector(`${this.getPreferenceSelector(preferenceId)} .settings-context-menu-btn`);
215203
if (!settingsContextMenuBtn) {
216204
throw new Error(`Could not find context menu button for element with preference id "${preferenceId}"`);
@@ -223,4 +211,19 @@ export class TheiaPreferenceView extends TheiaView {
223211
return resetPreferenceButton;
224212
}
225213

214+
async waitForModified(preferenceId: string): Promise<void> {
215+
await this.activate();
216+
const viewElement = await this.viewElement();
217+
await viewElement?.waitForSelector(`${this.getPreferenceGutterSelector(preferenceId)}${this.modificationIndicator}`, { timeout: this.customTimeout });
218+
}
219+
220+
async waitForUnmodified(preferenceId: string): Promise<void> {
221+
await this.activate();
222+
const viewElement = await this.viewElement();
223+
await viewElement?.waitForSelector(`${this.getPreferenceGutterSelector(preferenceId)}${this.modificationIndicator}`, { state: 'detached', timeout: this.customTimeout });
224+
}
225+
226+
private getPreferenceGutterSelector(preferenceId: string): string {
227+
return `${this.getPreferenceSelector(preferenceId)} .pref-context-gutter`;
228+
}
226229
}

examples/playwright/tests/theia-preference-view.test.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,44 +38,63 @@ test.describe('Preference View', () => {
3838
const preferences = await app.openPreferences(TheiaPreferenceView);
3939
const preferenceId = PreferenceIds.DiffEditor.MaxComputationTime;
4040

41-
await preferences.resetStringPreferenceById(preferenceId);
41+
await preferences.resetPreferenceById(preferenceId);
4242
expect(await preferences.getStringPreferenceById(preferenceId)).toBe(DefaultPreferences.DiffEditor.MaxComputationTime);
4343

4444
await preferences.setStringPreferenceById(preferenceId, '8000');
4545
await preferences.waitForModified(preferenceId);
4646
expect(await preferences.getStringPreferenceById(preferenceId)).toBe('8000');
4747

48-
await preferences.resetStringPreferenceById(preferenceId);
48+
await preferences.resetPreferenceById(preferenceId);
4949
expect(await preferences.getStringPreferenceById(preferenceId)).toBe(DefaultPreferences.DiffEditor.MaxComputationTime);
5050
});
5151

5252
test('should be able to read, set, and reset Boolean preferences', async () => {
5353
const preferences = await app.openPreferences(TheiaPreferenceView);
5454
const preferenceId = PreferenceIds.Explorer.AutoReveal;
5555

56-
await preferences.resetBooleanPreferenceById(preferenceId);
56+
await preferences.resetPreferenceById(preferenceId);
5757
expect(await preferences.getBooleanPreferenceById(preferenceId)).toBe(DefaultPreferences.Explorer.AutoReveal.Enabled);
5858

5959
await preferences.setBooleanPreferenceById(preferenceId, false);
6060
await preferences.waitForModified(preferenceId);
6161
expect(await preferences.getBooleanPreferenceById(preferenceId)).toBe(false);
6262

63-
await preferences.resetBooleanPreferenceById(preferenceId);
63+
await preferences.resetPreferenceById(preferenceId);
6464
expect(await preferences.getBooleanPreferenceById(preferenceId)).toBe(DefaultPreferences.Explorer.AutoReveal.Enabled);
6565
});
6666

67+
test('should be able to read, set, and reset Options preferences', async () => {
68+
const preferences = await app.openPreferences(TheiaPreferenceView);
69+
const preferenceId = PreferenceIds.Editor.RenderWhitespace;
70+
71+
await preferences.resetPreferenceById(preferenceId);
72+
expect(await preferences.getOptionsPreferenceById(preferenceId)).toBe(DefaultPreferences.Editor.RenderWhitespace.None);
73+
74+
await preferences.setOptionsPreferenceById(preferenceId, DefaultPreferences.Editor.RenderWhitespace.Boundary);
75+
await preferences.waitForModified(preferenceId);
76+
expect(await preferences.getOptionsPreferenceById(preferenceId)).toBe(DefaultPreferences.Editor.RenderWhitespace.Boundary);
77+
78+
await preferences.resetPreferenceById(preferenceId);
79+
expect(await preferences.getOptionsPreferenceById(preferenceId)).toBe(DefaultPreferences.Editor.RenderWhitespace.None);
80+
});
81+
6782
test('should throw an error if we try to read, set, or reset a non-existing preference', async () => {
6883
const preferences = await app.openPreferences(TheiaPreferenceView);
6984

7085
preferences.customTimeout = 500;
7186
try {
7287
await expect(preferences.getBooleanPreferenceById('no.a.real.preference')).rejects.toThrowError();
7388
await expect(preferences.setBooleanPreferenceById('no.a.real.preference', true)).rejects.toThrowError();
74-
await expect(preferences.resetBooleanPreferenceById('no.a.real.preference')).rejects.toThrowError();
89+
await expect(preferences.resetPreferenceById('no.a.real.preference')).rejects.toThrowError();
7590

7691
await expect(preferences.getStringPreferenceById('no.a.real.preference')).rejects.toThrowError();
7792
await expect(preferences.setStringPreferenceById('no.a.real.preference', 'a')).rejects.toThrowError();
78-
await expect(preferences.resetStringPreferenceById('no.a.real.preference')).rejects.toThrowError();
93+
await expect(preferences.resetPreferenceById('no.a.real.preference')).rejects.toThrowError();
94+
95+
await expect(preferences.getOptionsPreferenceById('no.a.real.preference')).rejects.toThrowError();
96+
await expect(preferences.setOptionsPreferenceById('no.a.real.preference', 'a')).rejects.toThrowError();
97+
await expect(preferences.resetPreferenceById('no.a.real.preference')).rejects.toThrowError();
7998
} finally {
8099
preferences.customTimeout = undefined;
81100
}
@@ -86,8 +105,14 @@ test.describe('Preference View', () => {
86105
const stringPreference = PreferenceIds.DiffEditor.MaxComputationTime;
87106
const booleanPreference = PreferenceIds.Explorer.AutoReveal;
88107

89-
await expect(preferences.getBooleanPreferenceById(stringPreference)).rejects.toThrowError();
90-
await expect(preferences.setBooleanPreferenceById(stringPreference, true)).rejects.toThrowError();
91-
await expect(preferences.setStringPreferenceById(booleanPreference, 'true')).rejects.toThrowError();
108+
preferences.customTimeout = 500;
109+
try {
110+
await expect(preferences.getBooleanPreferenceById(stringPreference)).rejects.toThrowError();
111+
await expect(preferences.setBooleanPreferenceById(stringPreference, true)).rejects.toThrowError();
112+
await expect(preferences.setStringPreferenceById(booleanPreference, 'true')).rejects.toThrowError();
113+
await expect(preferences.setOptionsPreferenceById(booleanPreference, 'true')).rejects.toThrowError();
114+
} finally {
115+
preferences.customTimeout = undefined;
116+
}
92117
});
93118
});

0 commit comments

Comments
 (0)